【Linux】malloc和free底层的简单实现!!!

从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brkmmap(当然在这里是不考虑共享内存)

  1. brk是将数据段(.data)的最高地址指针_edata往高地址推;
  2. mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存。
    注:

  3. 在开辟空间的时候只是在进程的虚拟地址空间内开辟指定大小的内存,但是并没有实际在物理内存上面开辟空间,只有当对开辟的内存空间进行访问的时候才会在物理内存上面开辟实际的空间。例如:假如开辟的空间一直没有使用,那么在物理内存上面始终没有实际的空间。

  4. 在这之间当对开辟的内存进行第一次访问的时候会发生缺页中断,这时候系统就会在指定的空间进行开辟内存,然后再将物理内存的地址映射到虚拟地址上面。

    当发生缺页中断的时候系统会干什么?
    1、检查要访问的虚拟地址是否合法
    2、查找/分配一个物理页
    3、填充物理页内容(读取磁盘,或者直接置0,或者啥也不干)
    4、建立映射关系(虚拟地址到物理地址)

情况1:

当使用malloc小于128k的内存,使用brk分配内存,将_edata往高地址推(只分配虚拟空间,不对应物理内存(因此没有初始化),第一次读/写数据时,引起内核缺页中断,内核才分配对应的物理内存,然后虚拟地址空间建立映射关系)
这里写图片描述

在开辟较小的空间的时候会直接将_edata寄存器的指向向髙地址一定指定大小的位置,然后将这个区域映射到虚拟内存地址空间内。但是这时候这个位置并没有实际的物理内存,只有当使用到这块内存的时候才会在物理内存上面开辟空间。

情况2:
当开辟的空间大小大于128K的时候并不是使用brk系统来移动_edata指向来开辟空间,而是使用mmap系统在堆栈之间的共享区直接开辟指定大小的空间(虚拟空间)。
这里写图片描述

同样,在开辟空间之后并没有实际的物理内存空间,当使用的时候才会初始化。

free

当需要销毁的时候,使用mmap开辟的空间会直接释放,如果在物理内存上面开辟的有实际的内存的话也会一起释放。当时使用brk开辟的内存只能依次释放,比如:释放b的时候可以直接释放虚拟内存和物理内存,但是在释放a的时候如果在a的上面还有开辟的空间,那么a这块空间并不会被释放,因为在a的上面还有开辟的空间,但是a这块空间是可以复用的,那么如果在下次开辟空间的时候又开辟了和啊大小的空间,那么很有可能系统就会直接将a这块空间映射到虚拟空间内。
因为使用brk开辟的内存必须等髙地址的内存释放之后才会释放,这也是内存碎片产生的原因。

释放a:
这里写图片描述

释放b:
这里写图片描述

当c也释放的时候,那么_edata指向就会重新回退到含有开辟空间的位置上面。
这里写图片描述

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Doctor_xiong/article/details/79948171
个人分类: Linux
上一篇【Linux】读写锁!!
下一篇【Linux】进程组、作业、回话、守护进程的基本概念!!
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭