之前一段时间翻阅过一些内存分配的资料,这次终于能将其整理记录下来了。

c标准库里有两个耳熟能详的函数,用于对堆空间的内存进行分配和释放,它们分别是:

  1. malloc。负责分配一个指定大小的一块内存给调用的程序,函数返回一个指向这块内存的指针。
  2. free。对函数参数指向的内存块进行释放操作。

需要说明的是,不管是malloc还是free,这些函数都是c标准库提供给我们的,而不是操作系统的API。对于堆上的内存管理,操作系统(Linux)提供以下两个接口:

  1. sbrk。用于扩张和收缩堆,本质上就是移动指向堆顶的指针。把指针向高地址移动就是在扩张堆、向低地址移动就是在收缩堆。
  2. mmap、munmap。用于内存映射和取消内存映射,对于大块的内存申请,直接调用mmap申请一个内存段更加高效。

显然,malloc的实现是基于操作系统提供的API的,也就是上面提到的那两个syscall。而且,一般考虑到会频繁的进行内存分配,我们往往希望能尽量减少syscall的次数。于是,通常的策略是如下。

一般地,实现会在内部维持了一个空闲内存块的链表,当我们通过malloc申请一块内存,我们先在这个链表里进行搜索,如果找到符合大小的内存块,就将这个内存块返回给调用程序。否则,当在空闲链表中搜索不到满足要求的内存块,说明当前堆的大小不够用了,调用syscall以扩张堆的大小,并重新搜索内存块。当通过free释放内存的时候,则将内存块返回给这个空闲链表。空闲链表可能会有一些策略,用来在未来的某一个时候,通过syscall将这些空闲的内存重新归还给操作系统。

不同的malloc/free的实现,主要是在如何组织这个空闲内存块的链表上有所不同。关于glibc的malloc可以参考这篇文章:Glibc内存管理

在清楚malloc内部做了什么之后,就可以搞明白一些诡异的问题了。比如说,重现引用一块已经free掉的内存,为什么有时候会报段错误,有时候会崩溃,有时候什么事都没发生?

首先要说明的是操作系统的内存管理是段页式的,既分段也分页。而通常一个程序的内存段有:代码段、静态数据全局数据段、堆、栈等,而程序所能访问的地址必须是在OS已经分配的内存段中。如果访问的地址不在已存在的段内,就会报我们熟悉的段错误。当通过free将内存释放时,分配程序有可能为了重新利用这块内存而缓存着它,也有可能将这块内存真正的归还给操作系统。如果内存块被真正的归还给操作系统,比如free操作导致了堆的收缩,或是在free中调用了munmap取消了一个内存映射。这时候如果有一个指针指向这块内存地址,对它引用就会导致段错误。

不过大多数情况下,free掉的内存块不是立即归还给OS,而是被分配程序(malloc)插入到空闲内存块链表中缓存起来,等待再次被利用。有的实现(例如glibc的ptmalloc)为了内存空间的复用,会在这个内存块里面记录下指向链表前后节点的指针等信息。这时候如果我们对free掉的内存块重新执行写操作就有可能会改写这部分信息,导致这个内存块被写坏,破坏了空闲链表的结构,因此就有可能引起崩溃。

关于malloc的一些想法的更多相关文章

  1. C——malloc & free(转载自bccn C语言论坛)

    原帖及讨论:http://bbs.bccn.net/thread-82212-1-1.html 原文链接:http://www.bccn.net/Article/kfyy/cyy/jszl/20060 ...

  2. 浅谈C中的malloc和free

    转自http://bbs.bccn.net/thread-82212-1-1.html非常感谢作者 浅谈C中的malloc和free 在C语言的学习中,对内存管理这部分的知识掌握尤其重要!之前对C中的 ...

  3. C语言二重指针与malloc

    (内容主要源于网上,只是加入了些自己的剖析) 假设有一个二重指针: char **p; 同时有一个指针数组 char *name[4]; 如何引用p呢? 首先我们有程序代码如下 #include &l ...

  4. (转)Free函数的参数一定要是malloc返回的那个指针

    Free函数的参数一定要是malloc返回的那个指针   之前认为只要free的参数在malloc分配的区域之内就可以了, 现在发现不对的.在嵌入式里分配堆都是按照块来的,只要在这个块内系统就能识别, ...

  5. 关于malloc和free函数的用法

    原文:http://blog.pfan.cn/vfdff/33507.html 个人总结 在C语言的学习中,对内存管理这部分的知识掌 握尤其重要!之前对C中的malloc()和free()两个函数的了 ...

  6. 数据结构基础——指针及动态内存分配(malloc)

    一.指针 C语言中的指针是一种数据类型,比如说我们用int *a;就定义了一个指针a,它指向一个int类型的数.但是这个指针是未初始化的,所以,一般的,我们都在创建指针时初始化它,以免出错,在还不吃的 ...

  7. new与malloc的区别,以及内存分配浅析

      从函数声明上可以看出.malloc 和 new 至少有两个不同: new 返回指定类型的指针,并且可以自动计算所需要大小.比如: 1 2 3 int *p; p = new int; //返回类型 ...

  8. C语言中 malloc函数用法

    一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...

  9. malloc&&free的系统运行机制及其源代码的理解

    一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...

随机推荐

  1. X86 Booting Sequence

    1.BIOS 0xFFFF0 電源正常啟動後,x86 CPU 會先執行 0xFFFF0,也就是 BIOS ROM 的進入點.由於 0xFFFF0 ~ 0xFFFFF 只有少的很可憐的 16 bytes ...

  2. js 小数相加

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat=&qu ...

  3. jquery checkbox 实现单选

    最近在用javascript的时候发现网上实现checkbox单选的代码都已经过时了. 用着几年前的代码发现根本不行了 原因是jquery api已经更改 http://api.jquery.com/ ...

  4. IE6不支持min-heightt和min-width的解决办法

    IE6不支持min-height的解决办法 最小高度min-height是很有用的,但IE6却不支持.真烦人.有没有办法呢? 我们可以利用IE6不识别!important来实现: height:aut ...

  5. 如何:在 ASP.NET 网页中检测浏览器类型

    https://msdn.microsoft.com/zh-cn/library/3yekbd5b(VS.80).aspx private void Button1_Click(object send ...

  6. wf(五)

    测试工作流: 运用wf(四)的solution: 创建单元测试项目: 1.选择HelloWorkflow解决方案,右键选择添加新建项目:选择单元测试模板,命名为HelloWorkflow.Tests. ...

  7. Radmin Server-3.5 完美绿色破解版(x32 x64通用) 第三版 + 单文件制作方法

    Radmin Server v3.5 汉化破解绿色版(x32 x64通用) 第三版 下载链接: https://pan.baidu.com/s/1qYVcSQo 2016年7月8日更新第三版1.修复在 ...

  8. Win10 + Nginx 1.10 + PHP 7 + Redis 配置方法

    软件包版本 软件 版本 - 链接 - Nginx nginx-x32-1.10.2.zip 下载 PHP php-7.0.12-nts-Win32-VC14-x64 下载 Redis php_redi ...

  9. HQL查询——select子句

    select子句 select子句用于选择指定的属性或者直接选择某个实体,当然select选择的属性必须是from之后持久化类包含的属性: select p.name from Person as p ...

  10. JavaScript对象的chapterI

    对象: 对象就是由一些彼此相关的属性和方法集合在一起而构成的一个数据实体. 一.本地对象: 1.Date——日期对象 var myDate = new Date(); myDate.getFullYe ...