Linux系统---简易伙伴系统

顾得泉:个人主页
个人专栏:《Linux操作系统》 《C/C++》 《LeedCode刷题》
键盘敲烂,年薪百万!
一、题目要求
1.采用C语言实现
2.伙伴系统采用free_area[11]数组来组织。要求伙伴内存最小为一个页面,页面大小为4KB,最大为4MB,即1024个页面。描述一个空闲伙伴内存块的数据结构为
struct chunk
{unsigned int power; //内存块大小的2次幂指数,如12,13,...,22unsigned int start; //内存块的起始地址struct chunk* next; //后向指针Struct chunk* prev; //前向指针}
3.如何辨识两个内存块c1和c2互为伙伴(buddy)?
条件1:c1.power=c2.power,即两个块的大小相同;
条件2:c1和c2的地址start(二进制)的第power位不同,其他位完全相同。比如,大小为256KB的两个伙伴,一个地址为0x0000,0000,另一个为0x0004,0000,这两个地址的第18位(二进制位,从0开始起位)一个为0,一个为1,其余位完全相同,因此它们互为buddy。
再如,大小为256KB的两个伙伴,一个地址为0x0008,0000,另一个为0x000C,0000,它们的第power位,即第18位一个为0,一个为1,其余位完全相同。

而地址为0x4,0000和0x8,0000的chunk不是伙伴,尽管它们是相邻的。
因此可以设计判断两个chunk是否是伙伴的函数:
int isBuddy(struct chunk* c1, struct chunk* c2){if(c1->power!=c2->power)return 0;if((c1->start^c2->start)>>c1->power!=1) //先异或,再移位return 0;return 1;}
二、模块描述
本文实现了一个内存管理程序,用于分配和释放内存块。它使用了内存池技术,通过将内存块划分为大小为2^n的块来提高内存分配的效率。
程序中定义了一个结构体chunk,表示内存块,包含以下成员变量:
power:表示内存块的大小,即2^n。start:表示内存块的起始地址。next:指向下一个内存块的指针。prev:指向上一个内存块的指针。
程序还定义了一个全局数组free_area,用于存储空闲的内存块。数组的索引表示内存块的大小,数组的元素是指向对应大小的内存块链表的头指针。
程序提供了以下函数:
is_buddy(struct chunk *c1 , struct chunk *c2):判断两个内存块是否为“伙伴”关系,即它们的power相同且它们的起始地址相邻。init():初始化内存池,将最大内存块分配给free_area[8]。pick(unsigned int k):从free_area中选择一个大小为2^k的内存块,并将其分割成两个大小为2^(k-1)的内存块。allocate(unsigned int req):请求分配一个大小为req字节的内存块,如果无法满足请求,则返回NULL。release(struct chunk *c):释放一个内存块,将其与相邻的伙伴内存块合并,并更新free_area。check():打印当前内存池的状态,包括每个大小的内存块链表。
在main()函数中,首先调用init()函数初始化内存池,然后依次请求分配100KB、256KB和500KB的内存块,并打印分配前后的内存池状态。最后,释放这些内存块,并再次打印内存池状态。
三、代码实现
#include <stdio.h>
#include <stdlib.h>struct chunk{unsigned int power;unsigned int start;struct chunk *next;struct chunk *prev;
};struct chunk* free_area[11];int is_buddy(struct chunk *c1 , struct chunk *c2)
{if(c1 -> power != c2 -> power) return 0;if((c1 -> start ^ c2 -> start) >> c1 -> power != 1) return 0;return 1;
}void init()
{for(int i = 0 ; i < 11 ; i ++)free_area[i] = NULL;struct chunk *max_chunk = (struct chunk*) malloc(sizeof(struct chunk));max_chunk -> power = 20;max_chunk -> start= 0;max_chunk -> next = NULL;max_chunk -> prev = NULL;free_area[8] = max_chunk;
}struct chunk *pick(unsigned int k)
{struct chunk *c = NULL;struct chunk *left = NULL;struct chunk *right = NULL;int i;for(i = k ; i <= 10 ; i ++){if(free_area[i] != NULL){c = free_area[i];free_area[i] = c -> next;break;}}if(i > 10){printf("Failed to pick up a trunk\n");return NULL;}for(int j = i - 1 ; j >= k ; j --){left = (struct chunk*)malloc(sizeof(struct chunk));left -> power = c -> power - 1;left -> start = c -> start;left -> next = free_area[j];left -> prev = NULL;if(free_area[j] != NULL){free_area[j] -> prev = left;}free_area[j] = left;right = (struct chunk *) malloc(sizeof (struct chunk));right -> power = c -> power - 1;right -> start = c -> start + (1 << right -> power);right -> next = NULL;right -> prev = NULL;free(c);c = right;}return c;
}struct chunk * allocate(unsigned int req){unsigned int power = 0;while((1 << power) < req)power ++;return pick(power - 12);}void release(struct chunk *c)
{unsigned int k = c -> power - 12;struct chunk * buddy = NULL;int merged = 1;while(merged){merged = 0;buddy = free_area[k];while(buddy != NULL){if(is_buddy(c , buddy)){c -> power ++;if(buddy -> prev == NULL)free_area[k] = buddy -> next;else buddy -> prev -> next = buddy -> next;if(buddy -> next != NULL)buddy -> next -> prev = buddy -> prev;if(c -> start > buddy -> start) c -> start = buddy -> start;free(buddy);merged = 1;k ++;break;}buddy = buddy -> next;}}c -> next = free_area[k];if(free_area[k] != NULL)free_area[k] -> prev = c;free_area[k] = c;
}void check()
{for(int i = 0 ; i < 11 ; i ++){printf("free_area[%d]: " , i);struct chunk * chunk = free_area[i];while(chunk != NULL){printf("(%u , %x) ->" , chunk -> power , chunk -> start);chunk = chunk -> next;}printf("NULL\n");}printf("\n");
}int main()
{init();printf("inintal state\n");check();struct chunk *c100 = allocate(100 * 1024);printf("ask for 100kb allocate\n");check();struct chunk *c256 = allocate(256 * 1024);printf("ask for 256kb allocate\n");check();struct chunk *c500 = allocate(500 * 1024);printf("ask for 500kb allocate\n");check();release(c100);printf("release c100\n");check();release(c256);printf("release c256\n");check();release(c500);printf("release c500\n");check();
}
四、结果展示

首先开辟了一块1M大小的空间:

请求分配100KB的内存块:

请求分配256KB的内存块:

请求分配500KB的内存块:

释放100KB的内存块:

释放256KB的内存块:

释放500KB的内存块:

到此所有操作就结束了。
结语:Linux系统中实现简易的伙伴系统的分享到这里就结束了,希望本篇文章的分享会对大家的学习带来些许帮助,如果大家有什么问题,欢迎大家在评论区留言~~~
相关文章:
Linux系统---简易伙伴系统
顾得泉:个人主页 个人专栏:《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、题目要求 1.采用C语言实现 2.伙伴系统采用free_area[11]数组来组织。要求伙伴内存最小为一个页面,页面大小为4KB…...
Redis使用Lua脚本
Lua脚本 redis可以支持lua脚本,可以使用lua脚本来将几个命令整合为一个整体来执行,这样可以使得多个命令原子操作,且可以减少网络开销 Lua的数据类型 Lua是一个动态类型的语言,一个变量可以存储任何类型的值,类型有&am…...
macos安装metal 加速版 pytorch
categories: [Python] tags: Python MacOS 写在前面 试试 m3 的 metal 加速效果如何 Mac computers with Apple silicon or AMD GPUsmacOS 12.3 or laterPython 3.7 or laterXcode command-line tools: xcode-select --install 安装 Python: conda-forge brew install minif…...
【学习笔记】lyndon分解
摘抄自quack的ppt。 这部分和 s a sa sa的关联比较大,可以加深对 s a sa sa的理解。 Part 1 如果字符串 s s s的字典序在 s s s以及 s s s的所有后缀中是最小的,则称 s s s是一个 lyndon \text{lyndon} lyndon串。 lyndon \text{lyndon} lyndon分解&a…...
21、命令执行
文章目录 一、命令执行概述1.1 基本定义1.2 原理1.3 两个条件1.4 命令执行漏洞产生的原因1.5 管道符号和通用命令符 二、远程命令执行2.1 远程命令执行相关函数2.2 远程命令执行漏洞的利用 三、系统命令执行3.1 相关函数3.2 系统命令执行漏洞利用 四、命令执行漏洞防御 一、命令…...
Qexo博客后台管理部署
Qexo博客后台管理部署 个人主页 个人博客 参考文档 https://www.oplog.cn/qexo/本地部署 采用本地Docker部署管理本地Hexo 下载代码包 若无法下载使用科学工具下载到本地在上传到服务器 wget https://github.com/Qexo/Qexo/archive/refs/tags/3.0.1.zip# 解压 unzip Qexo…...
最小生成树prim
最小生成树(三)Prim算法及存储结构_哔哩哔哩_bilibili 311 最小生成树 Prim 算法_哔哩哔哩_bilibili #include <iostream> #include <queue> #include <string> #include <stack> #include <vector> #include <set…...
实用篇 | 一文学会人工智能中API的Flask编写(内含模板)
----------------------- 🎈API 相关直达 🎈-------------------------- 🚀Gradio: 实用篇 | 关于Gradio快速构建人工智能模型实现界面,你想知道的都在这里-CSDN博客 🚀Streamlit :实用篇 | 一文快速构建人工智能前端展…...
Si24R03—低功耗 SOC 芯片(集成RISC-V内核+2.4GHz无线收发器)
Si24R03是一款高度集成的低功耗SOC芯片,其集成了基于RISC-V核的低功耗MCU和工作在2.4GHz ISM频段的无线收发器模块。 MCU模块具有低功耗、Low Pin Count、宽电压工作范围,集成了13/14/15/16位精度的ADC、LVD、UART、SPI、I2C、TIMER、WUP、IWDG、RTC等丰…...
C# Winform 日志系统
目录 一、效果 1.刷新日志效果 2.单独日志的分类 3.保存日志的样式 二、概述 三、日志系统API 1.字段 Debug.IsScrolling Debug.Version Debug.LogMaxLen Debug.LogTitle Debug.IsConsoleShowLog 2.方法 Debug.Log(string) Debug.Log(string, params object[]) …...
【Java 基础】27 XML 解析
文章目录 1.SAX 解析器1)什么是 SAX2)SAX 工作流程初始化实现事件处理类解析 3)示例代码 2.DOM 解析器1)什么是 DOM2)DOM 工作流程初始化解析 XML 文档操作 DOM 树 3)示例代码 总结 在项目开发中࿰…...
地图服务 ArcGIS API for JavaScript基础用法全解析
地图服务 ArcGIS API for JavaScript基础用法全解析 前言 在接触ArcGIS之前,开发web在线地图时用过Leaflet来构建地图应用,作为一个轻量级的开源js库,在我使用下来Leaflet还有易懂易用的API文档,是个很不错的选择。在接触使用Ar…...
docker学习(八、mysql8.2主从复制遇到的问题)
在我配置主从复制的时候,遇到了一直connecting的问题。 起初可能是我ip配置的不对,slave_io_running一直connecting。(我的环境:windows中安装了wsl,是ubuntu环境的,在wsl中装了miniconda,mini…...
React-hook-form-mui(三):表单验证
前言 在上一篇文章中,我们介绍了react-hook-form-mui的基础用法。本文将着重讲解表单验证功能。 react-hook-form-mui提供了丰富的表单验证功能,可以通过validation属性来设置表单验证规则。本文将详细介绍validation的三种实现方法,以及如何…...
【私域运营秘籍】4大用户调研方法,让你轻松掌握用户心理!
我们常说私域运营的核心是用户运营。根据二八法则,20%的超级用户贡献企业80%的利润。因此,企业应该根据用户的价值贡献来有针对性地进行运营。 然而,在实际的私域运营中,我们不仅需要找出贡献价值不同的用户,还可以从…...
2.8寸 ILI9341 TFTLCD 学习移植到STM32F103C8T6
2.8寸 ILI9341 TFTLCD 学习移植到STM32F103C8T6 文章目录 2.8寸 ILI9341 TFTLCD 学习移植到STM32F103C8T6前言第1章 LCD简介1.1 LCD硬件接口介绍 第2章 LCD指令介绍第3章 LCD 8080驱动方式3.1 8080写时序3.2 8080读时序 第4章 LCD 驱动代码部分4.1 修改代码部分4.2 代码工程下载…...
Java利用TCP实现简单的双人聊天
一、创建新项目 首先创建一个新的项目,并命名为聊天。然后创建包,创建两个类,客户端(SocketClient)和服务器端(SocketServer) 二、实现代码 客户端代码: package 聊天; import ja…...
软件压力测试的重要性与用途
在当今数字化的时代,软件已经成为几乎所有行业不可或缺的一部分。随着软件应用规模的增加和用户数量的上升,软件的性能变得尤为关键。为了确保软件在面对高并发和大负载时仍然能够保持稳定性和可靠性,软件压力测试变得至关重要。下面是软件压…...
【数据挖掘】国科大苏桂平老师数据库新技术课程作业 —— 第二次作业
1 设 F { A B → C , B → D , C D → E , C E → G H , G → A } F\{AB\rightarrow C,B\rightarrow D, CD\rightarrow E, CE\rightarrow GH, G\rightarrow A \} F{AB→C,B→D,CD→E,CE→GH,G→A},用推理的方法证明 F ∣ A B → G F\;|AB\rightarrow G F∣AB→…...
Qt + MySQL(简单的增删改查)
Qt编译MySql插件教程 帮助: SQL Programming QSqlDatabase 静态函数 1.drivers(),得到可以使用的数据库驱动名字的集合 [static] QStringList QSqlDatabase::drivers();2.addDatabase(),添加一个数据库实例 [static] QSqlDatabase QSql…...
养鸡场规划:如何计算所需农场数量
在养鸡业中,如何高效地管理和规划农场的使用是一个关键问题。最近,我遇到了一位养鸡场主的需求,他需要根据每天的鸡出栏数据来计算所需农场的数量。今天,我们就来探讨如何通过编程解决这个问题。 问题背景 假设你有一个包含以下数…...
[Android] 故宫陶瓷馆 v2.2.251126
[Android] 故宫陶瓷馆 v2.2.251126 链接:https://pan.xunlei.com/s/VOpHzrBozQgvaUJbdCkB20SMA1?pwdu338# 故宫陶瓷馆是故宫博物院官方出品的APP,以“时间轴”为核心骨架、全新技术手段打造的陶瓷馆,为你将展品带至手中、带至眼前。...
Nextion Library技术解析:嵌入式HMI轻量通信框架
1. Nextion Library 深度技术解析:面向嵌入式工程师的轻量级HMI通信框架 1.1 库定位与工程价值 Nextion Library 是一个专为 Nextion 系列智能串口屏设计的轻量级 C 库,核心目标是 在资源受限的 MCU 平台上(如 Arduino Uno、STM32F0/F1、ES…...
10:2026 AI变现实战总览:内容、工具、信息差三种变现闭环
作者: HOS(安全风信子) 日期: 2026-04-01 主要来源平台: GitHub 摘要: 提前剧透12大模块如何串联成3条可复制的赚钱路径。本文构建内容变现2.0闭环全图(Agentic生成)、工具/SaaS变现闭环全图(Ag…...
ESP-01s固件烧录与Arduino编程:从接线玄学到一键下载的避坑指南
1. ESP-01s模块入门:为什么你的接线总是出错? 第一次接触ESP-01s的朋友,十有八九会在烧录固件或上传程序时遇到各种莫名其妙的失败。我见过太多人把模块插上CH340就以为万事大吉,结果在电脑前折腾一整天都搞不定下载。这其实是因为…...
基于陷波滤波器的双惯量伺服系统机械谐振抑制Matlab Simulink仿真模型研究:算法原理...
(传递函数版)伺服系统基于陷波滤波器双惯量伺服系统机械谐振抑制matlab/Simulink仿真 1.模型简介模型为基于陷波滤波器的双惯量伺服系统机械谐振抑制仿真,采用Matlab R2018a/Simulink搭建 仿真模型由传递函数形式搭建,主要包括转速…...
实例 9:液体压强探究
实例 9:液体压强探究 功能介绍: 模拟U形管压强计探究液体内部压强规律。学生将探头放入液体不同深度,观察U形管高度差变化;更换不同密度的液体(水、盐水、酒精),对比压强大小。应用清晰展示“液体压强随深度增加而增大”及“液体压强与液体密度有关”的规律,并可计算具…...
Java 基础核心知识
文章目录1. 谈谈对AQS的理解2. fail-safe机制与fail-fast机制分别有什么作用3. new String("abc")到底创建了几个对象4. 对序列化和反序列化的理解5. 谈谈对Java中SPI的理解6. String、StringBuffer、StringBuilder区别7. Integer 的判断8. 深拷贝和浅拷贝9. 强引用、…...
BROADCHIP广芯 BCT0104EGD-TR QFN 转换器/电平移位器
特性 无需方向控制信号数据速率 24Mbps(推) 2Mbps(开漏) A端口1.65V至5.5V,B端口2.3V至5.5V(VCCA < VCCB) VCC隔离:若任一VCC接地,则两个端口均处于高阻抗状态 无需电源供应顺序,VCCA或VCCB可先斜坡上升 lOFF:支持部分断电模式操作 提供QF…...
AI建站工具怎么选?一篇讲透选型标准与对比逻辑
面对市面上五花八门的“智能建站”、“免代码建站”宣传,很多人越看越糊涂:到底哪个才是真的适合我?是选AI自动生成的,还是拖拽式更灵活?这篇不直接给答案,而是先提供一套通用的筛选标准,再帮你…...
