malloc()在操作系统中的实现
来源:互联网 发布:mac切换输入法 编辑:程序博客网 时间:2024/06/03 09:16
在大部分操作系统中,内存分配由以下两个简单的函数来处理:
void *malloc (long numbytes):该函数负责分配 numbytes 大小的内存,并返回指向第一个字节的指针。void free(void *firstbyte):如果给定一个由先前的 malloc 返回的指针,那么该函数会将分配的空间归还给进程的“空闲空间”。
malloc_init 将是初始化内存分配程序的函数。它要完成以下三件事:将分配程序标识为已经初始化,找到系统中最后一个有效内存地址,然后建立起指向我们管理的内存的指针。这三个变量都是全局变量:
int has_initialized = 0;void *managed_memory_start;void *last_valid_address;
清单 2. 分配程序初始化函数/* Include the sbrk function */ #include void malloc_init(){/* grab the last valid address from the OS */last_valid_address = sbrk(0);/* we don''t have any memory to manage yet, so *just set the beginning to be last_valid_address */managed_memory_start = last_valid_address;/* Okay, we''re initialized and ready to go */ has_initialized = 1;}
现在,为了完全地管理内存,我们需要能够追踪要分配和回收哪些内存。在对内存块进行了 free 调用之后,我们需要做的是诸如将它们标记为未被使用的等事情,并且,在调用 malloc 时,我们要能够定位未被使用的内存块。因此, malloc 返回的每块内存的起始处首先要有这个结构:
struct mem_control_block { int is_available; int size;};
现在,您可能会认为当程序调用 malloc 时这会引发问题 —— 它们如何知道这个结构?答案是它们不必知道;在返回指针之前,我们会将其移动到这个结构之后,把它隐藏起来。这使得返回的指针指向没有用于任何其他用途的内存。那样,从调用程序的角度来看,它们所得到的全部是空闲的、开放的内存。然后,当通过 free() 将该指针传递回来时,我们只需要倒退几个内存字节就可以再次找到这个结构。
在讨论分配内存之前,我们将先讨论释放,因为它更简单。为了释放内存,我们必须要做的惟一一件事情就是,获得我们给出的指针,回退 sizeof(struct mem_control_block) 个字节,并将其标记为可用的。这里是对应的代码:
//清单4. 解除分配函数void free(void *firstbyte) { struct mem_control_block *mcb; /* Backup from the given pointer to find the * mem_control_block */ mcb = firstbyte - sizeof(struct mem_control_block); /* Mark the block as being available */ mcb->is_available = 1; /* That''s It! We''re done. */ return;}如您所见,在这个分配程序中,内存的释放使用了一个非常简单的机制,在固定时间内完成内存释放。分配内存稍微困难一些。我们主要使用连接的指针遍历内存来寻找开放的内存块。这里是代码:
//清单 6. 主分配程序void *malloc(long numbytes) { /* Holds where we are looking in memory */ void *current_location; /* This is the same as current_location, but cast to a * memory_control_block */ struct mem_control_block *current_location_mcb; /* This is the memory location we will return. It will * be set to 0 until we find something suitable */ void *memory_location; /* Initialize if we haven''t already done so */ if(! has_initialized) { malloc_init(); } /* The memory we search for has to include the memory * control block, but the users of malloc don''t need * to know this, so we''ll just add it in for them. */ numbytes = numbytes + sizeof(struct mem_control_block); /* Set memory_location to 0 until we find a suitable * location */ memory_location = 0; /* Begin searching at the start of managed memory */ current_location = managed_memory_start; /* Keep going until we have searched all allocated space */ while(current_location != last_valid_address) { /* current_location and current_location_mcb point * to the same address. However, current_location_mcb * is of the correct type, so we can use it as a struct. * current_location is a void pointer so we can use it * to calculate addresses. */ current_location_mcb = (struct mem_control_block *)current_location; if(current_location_mcb->is_available) { if(current_location_mcb->size >= numbytes) { /* Woohoo! We''ve found an open, * appropriately-size location. */ /* It is no longer available */ current_location_mcb->is_available = 0; /* We own it */ memory_location = current_location; /* Leave the loop */ break; } } /* If we made it here, it''s because the Current memory * block not suitable; move to the next one */ current_location = current_location + current_location_mcb->size; } /* If we still don''t have a valid location, we''ll * have to ask the operating system for more memory */ if(! memory_location) { /* Move the program break numbytes further */ sbrk(numbytes); /* The new memory will be where the last valid * address left off */ memory_location = last_valid_address; /* We''ll move the last valid address forward * numbytes */ last_valid_address = last_valid_address + numbytes; /* We need to initialize the mem_control_block */ current_location_mcb = memory_location; current_location_mcb->is_available = 0; current_location_mcb->size = numbytes; } /* Now, no matter what (well, except for error conditions), * memory_location has the address of the memory, including * the mem_control_block */ /* Move the pointer past the mem_control_block */ memory_location = memory_location + sizeof(struct mem_control_block); /* Return the pointer */ return memory_location; }这就是我们的内存管理器。现在,我们只需要构建它,并在程序中使用它即可.多次调用malloc()后空闲内存被切成很多的小内存片段,这就使得用户在申请内存使用时,由于找不到足够大的内存空间,malloc()需要进行内存整理,使得函数的性能越来越低。聪明的程序员通过总是分配大小为2的幂的内存块,而最大限度地降低潜在的malloc性能丧失。也就是说,所分配的内存块大小为4字节、8字节、16字节、18446744073709551616字节,等等。这样做最大限度地减少了进入空闲链的怪异片段(各种尺寸的小片段都有)的数量。尽管看起来这好像浪费了空间,但也容易看出浪费的空间永远不会超过50%。
0 0
- malloc()在操作系统中的实现
- free函数在操作系统内存中的实现
- free函数在操作系统内存中的实现
- free函数在操作系统内存中的实现
- 数据结构在操作系统中的应用
- malloc 实现
- malloc实现
- malloc实现
- 模拟实现c语言中的动态内存分配malloc函数
- 嵌入式操作系统分析:浅析动态内存分配及Malloc/free的实现
- 嵌入式操作系统分析(六):浅析动态内存分配及Malloc/free的实现
- 无线技术在Linux操作系统中的应用
- Smartdrv在安装操作系统中的作用
- Linux 操作系统在NAS中的典型应用
- 在 Windows 操作系统中的已知安全标识符
- 隐藏在手机中的第二个操作系统
- 隐藏在手机中的第二个操作系统
- 隐藏在手机中的第二个操作系统
- [转]正则表达式总结
- build.gradle文件详解
- git rebase简介(基本篇)
- C++中的智能指针(上)
- 招聘人员中哪些话不能相信
- malloc()在操作系统中的实现
- 正则表达式基础
- SQLServer
- [BZOJ 3671][Noi2014]随机数生成器:贪心
- 学习网站
- 项目管理利器-maven
- [转]通过六个题目彻底掌握String
- 深度学习物体检测(八)——YOLO2
- GuestName处理方法