最新个人博客 shankusu.me

以下内容转载或参考或引用自

https://blog.csdn.net/zxx910509/article/details/62881131

一、malloc/free概述

malloc是在C语言中用于在程序运行时在堆中进行动态内存分配的库函数。free是进行内存释放的库函数。

1、函数原型

[cpp] view plain copy
  1. #include <stdlib.h>
  2. void *malloc(
  3. size_t size
  4. );
[cpp] view plain copy
  1. void free(
  2. void* memblock
  3. );

2、返回值

成功时,返回所分配存储空间的起始地址;返回值类型为void*,在C语言中可以把void*直接付给具体的类型,但是在C++中必须进行强制类型转换

失败时(内存不足时)返回NULL

size为0时,返回的指针不是NULL;但是除了free,别的地方不要使用这个指针。

3、使用示例

[cpp] view plain copy
  1. #include <stdlib.h>         /* For _MAX_PATH definition */
  2. #include <stdio.h>
  3. #include <malloc.h>
  4. void main( void )
  5. {
  6. char *string;
  7. /* Allocate space for a path name */
  8. string = malloc( _MAX_PATH );
  9. // In a C++ file, explicitly cast malloc's return.  For example,
  10. // string = (char *)malloc( _MAX_PATH );
  11. if( string == NULL )
  12. printf( "Insufficient memory available\n" );
  13. else
  14. {
  15. printf( "Memory space allocated for path name\n" );
  16. free( string );
  17. printf( "Memory freed\n" );
  18. }
  19. }

二、malloc实际分配的内存大小

malloc实际分配的内存会大于我们需要的size。主要由两方面因素决定:

1、字节对齐。会对齐到机器最受限的类型(具体的实现因机器而异)。

2、“块头部信息”。每个空闲块都有“头部”控制信息,其中包含一个指向链表中下一个块的指针、当前块的大小和一个指向本身的指针。为了简化块对齐,所有块的大小都必须是头部大小的整数倍,且头部已正确对齐。

在VC平台下由_CrtMemBlockHeader结构体实现。

以下为《C程序设计语言》中给出的通过union进行的头部实现,其中假定机器的受限类型为long。

[cpp] view plain copy
  1. typedef long Align;/*按照long类型的边界对齐*/
  2. union header/*块的头部*/
  3. {
  4. struct
  5. {
  6. union header *ptr;/*空闲块链表中的下一块*/
  7. unsigned size;/*本块的大小*/
  8. }s;
  9. Align x;/*强制块对齐*/
  10. };

说明:
(1)实际分配的内存块将多一个单元,用于头部本身。实际分配的块的大小被记录在头部的size字段中。

(2)size字段是必须的,因为malloc函数控制的块不一定是连续的,这样就不能通过指针算术运算计算其大小。

(3)malloc返回的是空闲块的首地址,而不是首地址。

三、malloc/free实现过程

1、空闲存储空间以空闲链表的方式组织(地址递增),每个块包含一个长度、一个指向下一块的指针以及一个指向自身存储空间的指针。( 因为程序中的某些地方可能不通过malloc调用申请,因此malloc管理的空间不一定连续。)

2、当有申请请求时,malloc会扫描空闲链表,直到找到一个足够大的块为止(首次适应)(因此每次调用malloc时并不是花费了完全相同的时间)。

3、如果该块恰好与请求的大小相符,则将其从链表中移走并返回给用户。如果该块太大,则将其分为两部分,尾部的部分分给用户,剩下的部分留在空闲链表中(更改头部信息)。因此malloc分配的是一块连续的内存。

4、释放时,首先搜索空闲链表,找到可以插入被释放块的合适位置。如果与被释放块相邻的任一边是一个空闲块,则将这两个块合为一个更大的块,以减少内存碎片。

四、实现

以下为《C语言程序设计语言》中给出的一种实现方法

1、malloc的实现

[cpp] view plain copy
  1. typedef union header Header;
  2. static Header base;/*从空链表开始*/
  3. static Header *freep = NULL;/*空闲链表的初始指针*/
  4. void *malloc(unsigned nbytes)
  5. {
  6. Header *p, *prevp;
  7. Header *morecore(unsigned);
  8. unsigned nunits;
  9. nunits = (nbytes+sizeof(Header)-1)/sizeof(Header) + 1;
  10. if((prevp = freep) == NULL) /* 没有空闲链表 */
  11. {
  12. base.s.ptr = freep = prevp = &base;
  13. base.s.size = 0;
  14. }
  15. for(p = prevp->s.ptr; ;prevp = p, p= p->s.ptr)
  16. {
  17. if(p->s.size >= nunits) /* 足够大 */
  18. {
  19. if (p->s.size == nunits)  /* 正好 */
  20. prevp->s.ptr = p->s.ptr;
  21. else  /*分配末尾部分*/
  22. {
  23. p->s.size -= nunits;
  24. p += p->s.size;
  25. p->s.size = nunits;
  26. }
  27. freep = prevp;
  28. return (void*)(p+1);
  29. }
  30. if (p== freep) /* 闭环的空闲链表*/
  31. if ((p = morecore(nunits)) == NULL)
  32. return NULL; /* 没有剩余的存储空间 */
  33. }
  34. }

说明:

(1)malloc实际分配的空间是Header大小的整数倍,并且多出一个Header空间用于放置Header

(2)式nunits = (nbytes+sizeof(Header)-1)/sizeof(Header) + 1中的减1是为了防止(nbytes+sizeof(Header))%sizeof(Header) == 0时,多分配了一个Header大小的空间

(3)第一次调用malloc函数时,freep为NULL,系统将创建一个退化的空闲链表,它只包含一个大小为0的块,且该块指向自己。任何时候,当请求空闲空间时,都将搜索空闲块链表。搜索从上一次找到空闲块的地方(freep)开始。该策略可以保证链表是均匀的。如果找到的块太大,则将其尾部返回给用户,这样,初始块的头部只需要修改size字段即可。

(4)任何时候,返回给用户的指针都指向块内的空闲存储空间,即比指向头部的指针大一个单元。

(5)sbrk不是系统调用,是C库函数。sbrk/brk是从堆中分配空间,本质是移动一个位置,向后移就是分配空间,向前移就是释放空间,sbrk用相对的整数值确定位置,如果这个整数是正数,会从当前位置向后移若干字节,如果为负数就向前若干字节。在任何情况下,返回值永远是移动之前的位置。在LINUX中sbrk(0)能返回比较精确的虚拟内存使用情况。链接:sbrk()/brk()--改变数据长度

(6)链接:brk()分配过程

2、morecore的实现

函数morecore用来向操作系统请求存储空间,其实现细节因系统的不同而不同。因为向系统请求存储空间是一个开销很大的操作,因此我们不希望每次调用malloc时都执行该操作,基于这个考虑,morecore函数请求至少NALLOC个单元。这个较大的块将根据需要分成较小的块。在设置完size字段后,morecore函数调用free函数把多余的存储空间插入到空闲区域中。

[cpp] view plain copy
  1. #define NALLOC 1024    /* 最小申请单元数 */
  2. static Header *morecore(unsigned nu)
  3. {
  4. char *cp;
  5. Header *up;
  6. if(nu < NALLOC)
  7. nu = NALLOC;
  8. cp = sbrk(nu * sizeof(Header));
  9. if(cp == (char *)-1)    /* 没有空间*/
  10. return NULL;
  11. up = (Header *)cp;
  12. up->s.size = nu;
  13. free((void *)(up+1));
  14. return freep;
  15. }

说明:

(1)没有存储空间时sbrk调用返回-1.因此需要将-1强制类型转换为char*类型,以便 与返回值进行比较。而且,强制类型转换使得函数不会受不同机器中指针表示的不同的影响。

3、free的实现

free函数从freep指向的地址开始,逐个扫描空闲链表,寻找可以插入空闲块的地方。该位置可能在链表的末尾或者两个空闲块之间。在任何一种情况下,如果被释放的块与另一空闲块相邻,则将这两个块合并。

[cpp] view plain copy
  1. void free(void *ap)
  2. {
  3. Header *bp,*p;
  4. bp = (Header *)ap -1; /* 指向块头 */
  5. for(p=freep;!(bp>p && bp< p->s.ptr);p=p->s.ptr)
  6. if(p>=p->s.ptr && (bp>p || bp<p->s.ptr))
  7. break;    /* 被释放的块在链表的开头或结尾*/
  8. if (bp+bp->s.size==p->s.ptr) /*与上一相邻块合并 */
  9. {
  10. bp->s.size += p->s.ptr->s.size;
  11. bp->s.ptr = p->s.ptr->s.ptr;
  12. }
  13. else
  14. bp->s.ptr = p->s.ptr;
  15. if (p+p->s.size == bp)/* 与下一相邻块合并 */
  16. {
  17. p->s.size += bp->s.size;
  18. p->s.ptr = bp->s.ptr;
  19. }
  20. else
  21. p->s.ptr = bp;
  22. freep = p;
  23. }

五、注意事项

链接:malloc/free使用注意事项

参考文献:

1、《C程序设计语言》

2、《C和指针》

3、《C和C++安全编码》

4、链接:如何实现一个malloc

C语言动态内存分配:(一)malloc/free的实现及malloc实际分配/释放的内存相关推荐

  1. linux 在指定区域分配内存 c语言,C语言动态内存分配:(一)malloc/free的实现及malloc实际分配/释放的内存...

    一.malloc/free概述 malloc是在C语言中用于在程序运行时在堆中进行动态内存分配的库函数.free是进行内存释放的库函数. 1.函数原型 #include void *malloc( s ...

  2. c语言malloc引用类型作参数,C语言动态内存函数的理解和总结

    第一:内存的使用 内存可以分为以下三个主要的部分:栈区.堆区.静态区 栈区(stack):存放的是局部变量.函数的形参等都是在该区上存放的. 堆区(heap):动态内存函数开辟的空间.比如malloc ...

  3. c语言分配多一个字符空间,关于C语言动态给字符串分配内存空间问题

    在动态分配的空间中如何输入字符串,关于C语言动态给字符串分配内存空间的问题相信很多朋友都不太了解,下面维维带来相关解答,赶紧看看吧. 用malloc来分配内存空间. 即输入几个字节的字符 系统就自动帮 ...

  4. c语言动态内存分配数组,【C】动态内存分配

    ## 动态内存分配的意义 C语言中的一切操作都是基于内存的 变量和数组都是内存的别名 内存分配由编译器在编译期间决定 定义数组的时候必须指定数组长度 数组长度是在编译期就必须确定的需求: 程序在运行过 ...

  5. C语言动态内存开辟详解(malloc,calloc,realloc,free,柔型数组)

    目录 一.概述 二.相关库函数的使用 1.malloc 2.calloc malloc vs. calloc 异同 3.free的使用 4.realloc 三.易错点 四.C\C++程序的内存开辟规则 ...

  6. C语言动态内存管理和动态内存分配函数

    给变量分配内存空间可分为静态内存分配和动态内存分配. 静态内存分配属于编译时给变量分配的空间,动态分配属于在程序运行时给变量分配的空间 静态分配属于栈分配,动态分配属于堆分配 运行效率上,静态内存比动 ...

  7. C语言-动态内存管理(malloc()、calloc()、realloc()、free())

    C语言 动态内存分配 文章目录 C语言 动态内存分配 前言 一.为什么存在动态内存分配? 二.动态内存函数的介绍 1.初识malloc()和free() 2.malloc()和free()的简单使用 ...

  8. C语言动态内存分配详解

    文章目录 前言 一.为什么存在动态内存分配 1.已掌握的内存开辟方式 2.上述开辟空间方式的特点 3.为什么存在动态内存分配 二.动态内存函数的介绍 1.malloc 2.free 3.calloc ...

  9. 浅谈C语言动态内存分配及柔性数组

    文章目录 前言 1.动态内存的简单介绍 1.动态内存分配是什么? 2.为什么存在动态内存分配? 3.动态内存分配具体方法 1.动态内存函数 2.动态内存注意事项 2.经典面试题分析 3.C/C++程序 ...

最新文章

  1. Visual Paradigm 教程[UML]:如何在SoaML中建模多方服务?
  2. ssh_exchange_identification: Connection closed by remote host 问题的解决 (转)
  3. 田志刚:所有大公司都是小公司(二)
  4. cool pyramid diagram
  5. 盘点大厂的那些开源项目 - 华为
  6. 【iVX 初级工程师培训教程 10篇文拿证】05 画布及飞机大战游戏制作
  7. 15什么时候你最想打人
  8. 魔鬼作坊第一部实践----第九课
  9. 八皇后问题初始思路python_【单人解谜】经典的八皇后问题解析
  10. 不用再为机翻头疼!sci论文写作翻译神器推荐
  11. 高斯模型MATLAB的实现,高斯混合模型GMM实现matlab
  12. 解决微信公众号accessToken白名单问题
  13. 【NPM】Building fresh packages运行很久都没反应
  14. 保护眼睛的颜色和各种背景颜色设置方法(转)
  15. 分享假如你买到缩水U盘了怎么办?认倒霉?肯定不能的!
  16. mysql创建联合主键
  17. Unity读取项目文件夹图片,PC端
  18. 仿滴滴打车时间选择器开始结束时间
  19. MATLAB小知识(三)——输出矩阵到TXT
  20. 笔记:《深入浅出统计学》第八、九章:概率密度、正态分布(高斯分布)

热门文章

  1. Java、JSP+BBS论坛系统的设计与实现
  2. Simulink 学习(一)
  3. 输入正整数n,输出n层数字金字塔。
  4. Windows10系统提速优化
  5. storm笔记:storm集群
  6. DataBinding快速入门(还在用findViewById?)
  7. 深入学习Java:关于List下标越界源码分析
  8. 学习python-mysql:报错AttributeError: module 'MySQLdb' has no attribute 'cursors'
  9. 【python学习】-matplotlib绘图如何将坐标轴刻度值设置为科学计数法形式
  10. 卡尔曼滤波原理二:扩展卡尔曼