malloc free

2024-06-11 15:58
文章标签 free malloc

本文主要是介绍malloc free,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  1. CosOS内核中使用一个内核堆来管理内存,内核通过kmalloc和kfree从内核堆中申请和释放内存。CosOS为用户态编写的库函数中也实现了用户态堆,应用程序通过malloc和free从堆中申请释放内存。  
  2.   
  3.        内核堆和用户态堆的算法类似,都通过调用alloc和free_int来操作堆。下面以代码和注释的形式详细介绍CosOS中 alloc和free_int这两个函数的实现。  
  4.   
  5.   
  6.   
  7.   
  8. 在堆中,可以用的空闲内存块成为hole,堆使用了一个链表来保存堆中所有可用的hole。Alloc函数就是在这个链表中查找到一个大小合适的hole然后根据请求分配的大小把hole切分成两部分,一部分返回给调用者使用,剩下的重新加入到链表中。  
  9.   
  10.   
  11. /*    alloc两个参数,size代表请求分配内存的大小,page_align代表请求内存空间的首地址是否必须页对齐,即地址是能被0x1000整除的。实现这个特性是因为内核中有些空间必须页对齐,例如页表、也目录。*/  
  12.   
  13. void *alloc(u32int size, u8int page_align)  
  14.   
  15.   
  16.   
  17. {  
  18.   
  19.   
  20.   
  21.          register struct hole *hp, *prev_ptr;  
  22.   
  23.   
  24.   
  25.          u32int old_base;  
  26.   
  27.   
  28.   
  29.          prev_ptr = NIL_HOLE;  
  30.   
  31.   
  32.   
  33.          hp = hole_head;  
  34.   
  35.   
  36.   
  37. //通过变量hole链表,查找一个合适的hole   
  38.   
  39.   
  40.   
  41. while(hp != NIL_HOLE)   
  42.   
  43.   
  44.   
  45.          {  
  46.   
  47.   
  48.   
  49.                    if(page_align)  
  50.   
  51.   
  52.   
  53.                    {  
  54.   
  55.   
  56.   
  57. //由于页数限制,页对齐实现部分代码省略。   
  58.   
  59.   
  60.   
  61.                    }else if (hp->h_len >= size)   
  62.   
  63.   
  64.   
  65.                    {  
  66.   
  67.   
  68.   
  69. //找到了一个足够大的hole,使用这个hole。   
  70.   
  71.   
  72.   
  73. //将其地址保存在临时变量old_base中,作为alloc的返回值,   
  74.   
  75.   
  76.   
  77.                             old_base =hp->h_base;     
  78.   
  79.   
  80.   
  81. //由于hole比请求的空间大,剩余部分需放入堆中。只需重新调整hole的首地址和长度即可  
  82.   
  83.   
  84.   
  85.                             hp->h_base +=size;   
  86.   
  87.   
  88.   
  89.                             hp->h_len -=size;  
  90.   
  91.   
  92.   
  93.   
  94.   
  95.   
  96. //记住使用使用过的内存当中,最高的地址,保存在high_watermark当中   
  97.   
  98.   
  99.   
  100.                             if(hp->h_base > high_watermark)  
  101.   
  102.   
  103.   
  104.                                      high_watermark= hp->h_base;  
  105.   
  106.   
  107.   
  108. //经过上面代码调整hole的大小之后,如果hole的大小为0,即hole的大小与请求大小相同,则将其从hole链表中移除。  
  109.   
  110.   
  111.   
  112.                             if (hp->h_len == 0)   
  113.   
  114.   
  115.   
  116.                                      del_slot(prev_ptr,hp);  
  117.   
  118.   
  119.   
  120. //返回分配内存块得首地址。   
  121.   
  122.   
  123.   
  124.                             return (void*)(old_base);  
  125.   
  126.   
  127.   
  128.                    }  
  129.   
  130.   
  131.   
  132.                    prev_ptr = hp;  
  133.   
  134.   
  135.   
  136.                    hp = hp->h_next;  
  137.   
  138.   
  139.   
  140.          }  
  141.   
  142.   
  143.   
  144. //若运行到这里,说明堆中没有合适的内存块,返回一个空指针。   
  145.   
  146.   
  147.   
  148.          return0;  
  149.   
  150.   
  151.   
  152. }  
  153.   
  154.   
  155.   
  156. free_int用于将首地址为base,长度为clicks的内存块释放,重新加入到堆的hole列表中。  
  157.   
  158.   
  159.   
  160. void free_int(u32int base, u32int clicks)  
  161.   
  162.   
  163.   
  164. {  
  165.   
  166.   
  167.   
  168.   struct hole*hp, *new_ptr, *prev_ptr;  
  169.   
  170.   
  171.   
  172. //如果要释放的内存块大小为0,则直接返回   
  173.   
  174.   
  175.   
  176.   if (clicks ==0)   
  177.   
  178.   
  179.   
  180.           return;  
  181.   
  182.   
  183.   
  184.   if ( (new_ptr= free_slots) == NIL_HOLE)   
  185.   
  186.   
  187.   
  188.        ASSERT(0);  
  189.   
  190.   
  191.   
  192. //将内存块设置成一个hole   
  193.   
  194.   
  195.   
  196. new_ptr->h_base = base;  
  197.   
  198.   
  199.   
  200.   new_ptr->h_len = clicks;  
  201.   
  202.   
  203.   
  204.   free_slots = new_ptr->h_next;  
  205.   
  206.   
  207.   
  208.   hp = hole_head;  
  209.   
  210.   
  211.   
  212.   
  213.   
  214.   
  215. //如果内存块得地址是当前hole链表中最小的或者hole链表为空,则把它插入到链表的第一个位置。  
  216.   
  217.   if (hp ==NIL_HOLE || base <= hp->h_base) {  
  218.   
  219.   
  220.   
  221. //插入到第一个位置   
  222.   
  223.   
  224.   
  225.          new_ptr->h_next = hp;  
  226.   
  227.   
  228.   
  229.          hole_head = new_ptr;  
  230.   
  231.   
  232.   
  233. //检测是否能与相邻的hole合并成一个更大的hole,这样可以减少内存碎片。   
  234.   
  235.   
  236.   
  237. merge(new_ptr);  
  238.   
  239.   
  240.   
  241.          return;  
  242.   
  243.   
  244.   
  245.   }  
  246.   
  247.   
  248.   
  249. //hole没有被加入到首位置,则执行下面代码   
  250.   
  251.   
  252.   
  253.   prev_ptr = NIL_HOLE;  
  254.   
  255.   
  256.   
  257. //hole链表中的hole是按照内存块首地址由低到高排序的,插入新的hole时必须保证插入之后链表还是有序的。因此需要找到一个合适的位置插入。  
  258.   
  259.   
  260.   
  261.   while (hp !=NIL_HOLE && base > hp->h_base) {  
  262.   
  263.   
  264.   
  265.          prev_ptr = hp;  
  266.   
  267.   
  268.   
  269.          hp = hp->h_next;  
  270.   
  271.   
  272.   
  273.   }  
  274.   
  275.   
  276.   
  277. //找到了合适的位置,插入其中   
  278.   
  279.   
  280.   
  281.   new_ptr->h_next = prev_ptr->h_next;  
  282.   
  283.   
  284.   
  285.   prev_ptr->h_next = new_ptr;  
  286.   
  287.   
  288.   
  289. //检测是否能与相邻的hole合并成一个更大的hole,这样可以减少内存碎片。   
  290.   
  291.   
  292.   
  293.   merge(prev_ptr);     
  294.   
  295.   
  296.   
  297. }  
  298.   
  299.   
  300.   
  301.   
  302.   
  303.   
  304. Hole合并的实现较为简单,只需检测hole的base加上size是否与下一hole的base相同即可。这里不详细介绍  
  305.   
  306.   
  307.   
  308. alloc和free_int是最核心最原始的两个函数。free_int使用时第二个参数需要确定释放内存的大小,而用户态的malloc、free中,free是不需要知道内存大小,只需传入需要释放的地址即可。  
  309.   
  310.   
  311.   
  312. 为了在使用free时无需知道内存块得大小也可以正确释放内存块,CosOS中采用的方法是,将内存块得大小保存在内存块首地址前得一个整型空间中,具体实现如下:  
  313.   
  314.   
  315.   
  316. //size为申请内存的大小   
  317.   
  318.   
  319.   
  320. void * malloc(u32int size)  
  321.   
  322.   
  323.   
  324. {  
  325.   
  326.   
  327.   
  328. //使用alloc从堆中申请内存时,多申请4个字节,用来保存内存块大小。   
  329.   
  330.   
  331.   
  332.          void *p= alloc(size + 4);  
  333.   
  334.   
  335.   
  336. //在返回内存块的前4个字节中(即一个整型中)保存内存块大小。   
  337.   
  338.   
  339.   
  340.          *((u32int*)p) = size;  
  341.   
  342.   
  343.   
  344. //返回这4个字节之后的地址,防止使用内存块时,大小被破坏。   
  345.   
  346.   
  347.   
  348.          return(void*)((u32int)p + 4);  
  349.   
  350.   
  351.   
  352. }  
  353.   
  354.   
  355.   
  356. void free(void *p)  
  357.   
  358.   
  359.   
  360. {  
  361.   
  362.   
  363.   
  364. //从内存块首地址的前4个字节中获取内存块的大小,保存在size中。   
  365.   
  366.   
  367.   
  368.          u32int size = *((u32int*)p - 1);  
  369.   
  370.   
  371.   
  372. //使用free_int释放这块内存。   
  373.   
  374.   
  375.   
  376.          free_int((u32int)p - 4, size + 4);  
  377.   
  378.   
  379.   
  380. }  
  381.   
  382.    
CosOS内核中使用一个内核堆来管理内存,内核通过kmalloc和kfree从内核堆中申请和释放内存。CosOS为用户态编写的库函数中也实现了用户态堆,应用程序通过malloc和free从堆中申请释放内存。内核堆和用户态堆的算法类似,都通过调用alloc和free_int来操作堆。下面以代码和注释的形式详细介绍CosOS中 alloc和free_int这两个函数的实现。在堆中,可以用的空闲内存块成为hole,堆使用了一个链表来保存堆中所有可用的hole。Alloc函数就是在这个链表中查找到一个大小合适的hole然后根据请求分配的大小把hole切分成两部分,一部分返回给调用者使用,剩下的重新加入到链表中。/*    alloc两个参数,size代表请求分配内存的大小,page_align代表请求内存空间的首地址是否必须页对齐,即地址是能被0x1000整除的。实现这个特性是因为内核中有些空间必须页对齐,例如页表、也目录。*/void *alloc(u32int size, u8int page_align){register struct hole *hp, *prev_ptr;u32int old_base;prev_ptr = NIL_HOLE;hp = hole_head;//通过变量hole链表,查找一个合适的holewhile(hp != NIL_HOLE) {if(page_align){//由于页数限制,页对齐实现部分代码省略。}else if (hp->h_len >= size) {//找到了一个足够大的hole,使用这个hole。//将其地址保存在临时变量old_base中,作为alloc的返回值,old_base =hp->h_base;   //由于hole比请求的空间大,剩余部分需放入堆中。只需重新调整hole的首地址和长度即可hp->h_base +=size; hp->h_len -=size;//记住使用使用过的内存当中,最高的地址,保存在high_watermark当中if(hp->h_base > high_watermark)high_watermark= hp->h_base;//经过上面代码调整hole的大小之后,如果hole的大小为0,即hole的大小与请求大小相同,则将其从hole链表中移除。if (hp->h_len == 0) del_slot(prev_ptr,hp);//返回分配内存块得首地址。return (void*)(old_base);}prev_ptr = hp;hp = hp->h_next;}//若运行到这里,说明堆中没有合适的内存块,返回一个空指针。return0;}free_int用于将首地址为base,长度为clicks的内存块释放,重新加入到堆的hole列表中。void free_int(u32int base, u32int clicks){struct hole*hp, *new_ptr, *prev_ptr;//如果要释放的内存块大小为0,则直接返回if (clicks ==0) return;if ( (new_ptr= free_slots) == NIL_HOLE) ASSERT(0);//将内存块设置成一个holenew_ptr->h_base = base;new_ptr->h_len = clicks;free_slots = new_ptr->h_next;hp = hole_head;//如果内存块得地址是当前hole链表中最小的或者hole链表为空,则把它插入到链表的第一个位置。if (hp ==NIL_HOLE || base <= hp->h_base) {//插入到第一个位置new_ptr->h_next = hp;hole_head = new_ptr;//检测是否能与相邻的hole合并成一个更大的hole,这样可以减少内存碎片。merge(new_ptr);return;}//hole没有被加入到首位置,则执行下面代码prev_ptr = NIL_HOLE;//hole链表中的hole是按照内存块首地址由低到高排序的,插入新的hole时必须保证插入之后链表还是有序的。因此需要找到一个合适的位置插入。while (hp !=NIL_HOLE && base > hp->h_base) {prev_ptr = hp;hp = hp->h_next;}//找到了合适的位置,插入其中new_ptr->h_next = prev_ptr->h_next;prev_ptr->h_next = new_ptr;//检测是否能与相邻的hole合并成一个更大的hole,这样可以减少内存碎片。merge(prev_ptr);   }Hole合并的实现较为简单,只需检测hole的base加上size是否与下一hole的base相同即可。这里不详细介绍alloc和free_int是最核心最原始的两个函数。free_int使用时第二个参数需要确定释放内存的大小,而用户态的malloc、free中,free是不需要知道内存大小,只需传入需要释放的地址即可。为了在使用free时无需知道内存块得大小也可以正确释放内存块,CosOS中采用的方法是,将内存块得大小保存在内存块首地址前得一个整型空间中,具体实现如下://size为申请内存的大小void * malloc(u32int size){//使用alloc从堆中申请内存时,多申请4个字节,用来保存内存块大小。void *p= alloc(size + 4);//在返回内存块的前4个字节中(即一个整型中)保存内存块大小。*((u32int*)p) = size;//返回这4个字节之后的地址,防止使用内存块时,大小被破坏。return(void*)((u32int)p + 4);}void free(void *p){//从内存块首地址的前4个字节中获取内存块的大小,保存在size中。u32int size = *((u32int*)p - 1);//使用free_int释放这块内存。free_int((u32int)p - 4, size + 4);}

这篇关于malloc free的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1051619

相关文章

HumanNeRF:Free-viewpoint Rendering of Moving People from Monocular Video 翻译

HumanNeRF:单目视频中运动人物的自由视点绘制 引言。我们介绍了一种自由视点渲染方法- HumanNeRF -它适用于一个给定的单眼视频ofa人类执行复杂的身体运动,例如,从YouTube的视频。我们的方法可以在任何帧暂停视频,并从任意新的摄像机视点或甚至针对该特定帧和身体姿势的完整360度摄像机路径渲染主体。这项任务特别具有挑战性,因为它需要合成身体的照片级真实感细节,如从输入视频中可能

delphi : 窗体的close,free,destroy的区别

一、我用application.create(TForm2,Form2)语句,创建了Form2,可是调用了Form2.close后,重新调用Form2.show. 刚才所创建的Form2仍然存在。问为了节约资源,应该怎样使用close,free,destroy. 三者的关系是什么? 1、Action:=caFree。 2、 with TForm1.Create(Application) do

C语言动态内存空间分配(malloc,calloc,realloc,free)

为了代码观感美观,我将代码部分的注释删了 malloc #include<stdio.h>#include<stdlib.h>#include<errno.h>//使用动态内存分配函数的注意事项://1.要判断指针是否为空指针,如果没有成功开辟动态内存空间,则不能继续使用该指针//2.分配的动态内存空间的数量要大于等于赋值的元素的数量,不能造成动态内存的越界访问//3.动态内存空间中

【SPOJ】1825 Free tour II 点分治

传送门:【SPOJ】1825 Free tour II 题目分析:敲了两遍。。。 本题是论文题,具体见漆子超论文《分治算法在树的路径问题中的应用》。 在以root为根的第 i 棵子树上,我们用G[ i ,j ]表示root的第 i 棵子树的路径上严格有 j 个黑点的路径的最长长度。用F[ i ,j ]表示在root为根的第 i 棵子树的路径上不超过 j 个黑点的路径的最长长度。因

Linux malloc内存分配实现原理

目录   一、用户进程虚拟内存空间布局 二、malloc工作原理 2.1 malloc实现流程 2.1.1 brk方式申请内存 2.1.2 mmap方式分配内存 2.2 核心代码 2.3 malloc分配物理内存的时机 2.4 malloc分配的实际内存大小 三、虚拟内存与物理内存 3.1 如何建立映射 3.2 分配物理内存 3.3 物理内存访问 四、new和mall

阅读笔记(五)多线程无锁的C++实现《Lock-Free Data Structures》

1. 前言   本文介绍使用C++实现多线程中无锁算法的实现和优化过程。 2. 无锁&CAS   在多线程程序中,加锁是一种必要的手段,由于保证数据操作的正确性(原子性)。但是这也在很多时候带来了性能的极度下降,因为所有共享数据的操作均需要加锁,有些时候会严重影响性能,比如当读键盘或者一些较慢的I/O操作时,锁会延误了其他线程的操作。更糟糕的是,不当操作可能会带来死锁。   首先介绍最经典

malloc和new的区别是什么?

目录 前言 ​编辑 1. 语言级别 2. 内存分配和初始化 3. 返回类型 4.失败时的行为 5. 释放内存 6. 运用场景 前言 malloc 是 C 语言的内存分配函数,简单但不支持对象初始化。new 是 C++ 中的运算符,功能更强大,能够同时进行内存分配和对象初始化,并且支持异常处理。 1. 语言级别 malloc:是 C 语言中的标准库函数,用于分配

malloc/free 和 new/delete的区别

malloc/free 和 new/delete 是 C++ 中两种不同的动态内存管理方法,它们有一些关键的区别: 1. 内存分配和释放机制 malloc 和 free: 函数: malloc 是一个 C 标准库函数,用于从堆中分配指定大小的原始内存块。它返回一个 void* 指针,指向分配的内存块的起始位置。free 用于释放由 malloc 分配的内存,防止内存泄漏。初始化: mallo

浅谈free函数的用法

free() 函数一般是用来释放 malloc()函数或者是calloc函数申请的内存空间. 但是有一点值得注意的是,比如说 int * p; p = (int *) malloc (sizeof (int)); free (p); 虽然用了free()函数释放了内存但是p指针依然指向着当时给它分配的内存空间, 所以一般在free(p);后面加上p = NULL;这也是一个比较好的

kaggle平台free使用GPU

1、注册 请保证在【科学上网】条件下进入如下操作,只有在注册账户和手机号验证时需要。 step1:注册账户 进入kaggle官网:https://www.kaggle.com/,点击右上角【Register】进入注册页面 最好选择使用邮箱注册(!!!如果你先用goole注册,然后改成其他邮箱,再用其他邮箱登录时会报错,需要重新找回密码) 输入【邮箱】、【密码】和【用户名】后,勾选