c语言里面的free深度研究

(这篇文章呢,大家看一下就好,因为很多地方情况都不一样的!)

原先的问题是:

malloc 申请得到的内存后,再 free 释放它的时候,操作系统会立即收回那块内存吗?

一种解释:

1)C库老老实实地待在硬盘里,没法管这事。free()是库函数,没错。可这就给许多人错觉,以为,C自己把这事给办了。空间回收和空间分配一样,涉及到两块空间:虚拟空间与物理空间。虚拟空间是进程私有的,这没事,进程可以自行了断。但物理空间一共就一块,所有的进程都共用它。如果让每个进程自行做垃圾回收,那不就乱了套了?因此,我想象,库函数free()只是通知“可以回收啦”而没有真正回收空间。
2)当虚存释放空间时,如果系统立即做实存的回收,那会把系统累死。整个系统的运作效率大大降低。因此,现代系统的垃圾回收都有一些算法。这个好比你家门口的垃圾袋,并不是你放出去,小区清洁工立即拿走的。没有一个清洁工能对小区所有业主做到这样的服务,除非她是超人或机器猫。如果系统足够聪明,能识别某进程已经僵死并回收了它所占的空间,那为啥还剩下它的PCB呢?

stackOverflow上关于此问题的回答

问题是这样一段代码,运行会崩溃:

    int main()
    {

        unsigned char *p = (unsigned char*)malloc(4 * sizeof(unsigned char));
        memset(p, 0, 4);
        strcpy_s((char*)p, 9,"abcdabcd"); // **deliberately storing 8bytes**
        std::cout << p;
        free(p); // Obvious Crash, but I need how it works and why crash.
        //std::cout << p;
        return 0;
    }

我试了一下真的会停止运行。。(原因在文章最后)
先介绍一下memset函数:

memset是计算机中C/C++语言函数。将s所指向的某一块内存中的前n个 字节的内容全部设置为ch指定的ASCII值, 第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为指向s的指针

函数原型:
void * memset ( void * ptr, int value, size_t num );
作用:

Fill block of memory
Sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).

参数具体介绍:

Parameters

  • ptr
    Pointer to the block of memory to fill.
  • value
    Value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.
  • num
    Number of bytes to be set to the value.size_t is an unsigned integral type

所以上面的:
unsigned char *p = (unsigned char*)malloc(4 * sizeof(unsigned char)); memset(p, 0, 4);
就是申请一块4个字节的内存然后初始化为0.

然后我们看解释是啥:

In many malloc/free implementations, free does normally not return the memory to the operating system (or at least only in rare cases). The reason is, that you will get gaps in your heap and thus it can happen, that you just finish off your 2 or 4 GB of virtual memory with gaps. This should be avoided of course, since as soon as the virtual memory is finished, you will be in really big trouble. The other reason of course is, that the OS can only handle memory chunks that are of a specific size and alignment. To be specific: Normally the OS can only handle blocks that the virtual memory manager can handle (most often multiples of 512 bytes e.g. 4KB).

  • free通常不会直接把申请的内存还给操作系统,因为,如果如果你这样做的话,堆内存里面会出现gap(这个下面有解释),所以可能出现的情况是:你把你几个G的虚拟内存都被gap用完了(一脸茫然。。不懂)。当然要避免这样的情况啦。不过还有一个原因就是,操作系统每次只能处理一块特定大小的区域。具体一点说就是操作系统会处理虚拟内存能处理的大小的内存区域,大多数是512B的整数倍,比如4KB。
    (update:可能的一个翻译是“碎片”)

关于gap:

最后一项gap,又称NoMansLand,是4byte(nNoMansLandSize=4)大小的一段区域,注意看最后几行注释就明白了,在这个结构后面跟的是用户真正需要的10byte数据区域,而其后还跟了一个4byte的Gap,那么也就是说用户申请分配的区域是被一个头结构,和一个4byte的gap包起来的。在释放这10byte空间的时候,会检查这些信息。Gap被分配之后会被以0xFD填充。检查中如果gap中的值变化了,就会以Assert fail的方式报错
// Buffer just before (lower than) the user's memory: unsigned char gap[nNoMansLandSize];

So returning 40 Bytes to the OS will just not work. So what does free do?

  • 所以呢,free 40B的内存操作系统是不会处理的!那么free是干啥的?

Free will put the memory block in its own free block list. Normally it also tries to meld together adjacent blocks in the address space. The free block list is just a circular list of memory chunks which have of course some administrative data in the beginning. This is also the reason, why managing very small memory elements with the standard malloc/free is not efficient. Every memory chunk needs additional data and with smaller sizes more fragmentation happens.

  • free会把这块内存块放到它自己的要free的内存块区域,通常它也会试着把相邻的区域合并到一起。
    free区域只是一个环形的内存块链,并且这块区域还要有管理的数据,这也是为啥用标准库里面的malloc/free函数处理小块的数据很低效。

The free-list is also the first place that malloc looks at when a new chunk of memory is needed. It is scanned before it calls for new memory from the OS. When a chunk is found that is bigger then the needed memory, it is just divided into two parts. One is returned to caller, the other is put back into the free list.

  • 要free的列表也是malloc要分配一块新的内存的时候,首先要遍历的区域,如果free表的区域够大的话,就会使用这块区域,多余的部分还是会放回freelist。

There are many different optimizations to this standard behaviour (for example for small chunks of memory). But since malloc and free must be so universal, the standard behaviour is always the fallback when alternatives are not usable. There are also optimizations in handling the free-list — for example storing the chunks in lists sorted by sizes. But all optimizations also have their own limitations.

但是啊,其实呢,上面程序崩溃的主要原因是,只分配了4Byte的空间却写入了9个Byte 的内容!
这样就会把后面的管理区域给覆盖掉,所以会出现问题!

根据上面的说法,我稍微修改了一下程序:

        unsigned char *p = (unsigned char*)malloc(10 * sizeof(unsigned char));
        memset(p, 0, 10);
        strcpy_s((char*)p, 9,"abcdabcd"); // **deliberately storing 8bytes**
        std::cout << p;
        free(p);

这样就可以正常运行啦!

并且有人在free的后面再次打印这个字符串,貌似有些机器可以打印出来,反正我试了一下直接乱码了。肯定是内存被回收了。

这篇文章呢,大家看一下就好,因为很多地方情况都不一样的!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容