从malloc到跑路

当我还是一个懵懂无知的少年时,内心也曾升起这样的疑问从malloc到跑路_第1张图片这内存咋来的捏❓

有个帅气的小哥哥给我甩了一篇博客:对,就是这篇,看完后总感觉意犹未尽,似乎少了点什么的样子。。。

还是从malloc开始

从malloc到跑路_第2张图片

  1. 如果申请的内存小于64B,先在当前进程的空闲块链表中查找,找到合适的就返回;
  2. 否则如果小于512B,就尝试合并碎片块,内存就像,挤挤还是有的;
  3. 但也有挤不出来的时候,就尝试处理最近刑满释放的块,size完全匹配就直接返回;
  4. 还没有怎么办呢?鲁迅说过:如果大于128KB,就找小弟要(mmap);如果小于128KB,也找小弟要(brk)

从malloc到跑路_第3张图片

给系统打call

 从malloc到跑路_第4张图片:喂,内核吗!再搞点内存来~

“这。。不是刚给过吗,怎么又来要从malloc到跑路_第5张图片,先给个假的吧,反正你不急着用!”

内核并没有立即分配物理内存,而是先返回虚拟内存给上层,真正分配要等有人往这块地址中写数据才开始。

迫不得已

不久之后,不知道哪个倒霉蛋开始往那个假地址写数据了,正好一脚踩中了内核埋的陷阱——缺页中断!

具体情况是这样的:上面派人拿着那个虚拟地址和数据,来内核层写入。写入的时候会分析虚拟地址的合法性(没错,就是自己给出去的),尝试计算出物理内存的地址,发现页表中映射关系不存在,就触发了缺页中断!

从malloc到跑路_第6张图片:“没办法了额,这次真的得给他了,不然说不过去了。”

伙伴算法

底层分配物理内存使用kmalloc(),大块通过伙伴算法分配,内核用这个算法维护了一堆块,就像这样的:

从malloc到跑路_第7张图片

 

伙伴算法分配器管理的空闲列表,分别为2^0 ~ 2^10个页, 即4KB~1MB。

申请空间依次从小到大在空闲列表上匹配,没找到就往下一个找,分割下一个大块,一部分返回,另一部分挂在对应链表上;

两个具有相同大小、物理地址连续、且从同一个大块中拆出来的块叫伙伴。从malloc到跑路_第8张图片

 

释放的时候先检查对应size的链表中是否有伙伴,有就合并;然后往下一个size的链表中找,继续检查伙伴合并,直到没有伙伴或者合并为了最大块,再把块挂到对应size的链表上;

因为伙伴的块大小都是固定的,能分能合,所以不存在外碎片问题。

slab/slub分配器

slab分配器也叫slab层,小块且需频繁分配释放的通过slab层分配,slab通常为2^n字节。slab提前分配好固定size的块,挂在链表上,分为已满列表、部分满、空闲,分配时先从部分满列表分配,没有则从空闲列表分配,再没有则开辟一个新的空闲列表分配。

slab缓存队列管理复杂,其用于管理内存的数据结构本身开销较大,在其基础上又做了改进,就有了slub:

        slub可以动态调整内存块大小(类似伙伴算法),支持合并小内存块为较大内存块,减少外碎片;

        slub为每cpu维护一个本地缓存,只有本地缓存没有空闲,才向全局缓存申请,可以减少线程间竞争。

对于应用层老大的内存需求,不敢不重视,所以都是按页分配内存,也就是是通过伙伴算法分配了,slab/slub分配器一般是内核自己内部用~

页表

一个页是4KB,一台机器如果有4GB内存的话,有多少个页?

1048576!从malloc到跑路_第9张图片

怎么把这些页管理起来呢?

从malloc到跑路_第10张图片

 我管理页的地址不就好了:

一个PTE(页表项)占4B,标识一页物理内存的起始地址,1024个PTE组成一张页表,一张页表大小也正好是4KB,可以维护1024*4KB个页的内存(4MB);

这样只需要1024个页表就能管理好高达4GB的内存!可是,这1024个页表也有点多,该怎么管理呢?类似地,我管理页表的地址不就好了:

一个PDE(页目录项)占4B,标识一张页表的起始地址,1024个PDE组成一张页目录表,一张页目录表大小也正好是4KB,可以维护1024*4MB内存,即4GB。这样,我只需要记录顶级的页目录表的起始地址就可以了,这个就叫页基址。每cpu都给他一个寄存器,存这个页目录基址,这样cpu访问进程的页就更快啦~从malloc到跑路_第11张图片

从虚拟地址到物理地址

从malloc到跑路_第12张图片

虚拟地址也叫线性地址,高10位表示页目录项偏移,最高级页目录基址 + 高10位 * 4B 即为页目录项地址;

页目录项里记录了对应页表基地址,页表基地址 + 中10位 * 4B 即为物理页地址;

物理页地址 + 低12位 即为真正的物理地址,这里映射操作由MMU硬件(内存管理单元)自动计算,快到起飞~

swap

    当然了,虚拟内存也是有限的,在物理内存不足时,内核会将不常用的页换出到磁盘上的swap分区,需要访问时再换入内存。

好像有点扯远了,刚刚在伙伴算法分配器那里,好像没有找到空闲内存页哎~

从malloc到跑路_第13张图片

跑路?

怎么办,交不了差,难道要我跑路?

是的,当系统内存不足时,内核会使用 OOM(Out of Memory)机制来释放一些内存。通常情况下,内核会杀掉低优先级进程以释放内存。这种情况下,释放内存的过程被称为 OOM-kill。 

再逼我,我疯起来,连自己都杀!

你可能感兴趣的:(链表,数据结构)