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

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. Database cannot be started in this edition of SQL Server" error when restoring a Microsoft Dynamics CRM database

    处理办法:http://support.microsoft.com/kb/2567984

  2. YbSoftwareFactory 代码生成插件【十三】:Web API 的安全性

    ASP.NET Web API 可非常方便地创建基于 HTTP 的 Services,这些服务可以非常方便地被几乎任何形式的平台和客户端(如浏览器.Windows客户端.Android设备.IOS等) ...

  3. iOS 图片的按照比例拉伸

    // 这是一个UIImage 的分类 (  UIImage+Extension.h   ) UIImage+Extension.h #import <UIKit/UIKit.h> @int ...

  4. ASP.NET Repeater嵌套Repeater实现菜单加载

    在KS系统中要实现从数据库中读取界面权限文件实现菜单.界面的动态加载. 效果图: ASP.NET界面代码 <div id="menu-container"> <a ...

  5. iOS开发直播需要的准备

    这里我们要研究直播技术首先需要对AVFoundation熟悉掌握 AVFoundation拍照和录制视频 AVFoundation中提供了很多现成的播放器和录音机,但是事实上它还有更加底层的内容可以供 ...

  6. Hello Spring Framework——依赖注入(DI)与控制翻转(IoC)

    又到年关了,还有几天就是春节.趁最后还有些时间,复习一下Spring的官方文档. 写在前面的话: Spring是我首次开始尝试通过官方文档来学习的框架(以前学习Struts和Hibernate都大多是 ...

  7. Boostrap

    基本认知: Boostrap绝对是目前最流行用得最广泛的一款框架.它是一套优美,直观并且给力的web设计工具包,可以用来开发跨浏览器兼容并且美观大气的页面. Bootstrap的优缺点: 缺点: 1. ...

  8. ANGULAR JS WATCH监听使用(详)

    ANGULAR 监听使用: 当angular数据模型发生变化时,我们需要如果需要根据他的变化触发其他的事件. $watch是一个scope函数,用于监听模型变化,当你的模型部分发生变化时它会通知你. ...

  9. Android 启动多个闹钟。

    Intent i=new Intent(TimeSetActivity.this,AlarmReceiver.class); PendingIntent pi = PendingIntent.getB ...

  10. <<Windows via C/C++>>学习笔记 —— 线程优先级【转】

    转自:http://www.cnblogs.com/wz19860913/archive/2008/08/04/1259807.html 每个线程都有一个“优先级”,范围是0-31,0为最低优先级,3 ...