【我的笔记】内存管理(二)分区方法(静态、动态、伙伴、Slab)

一、静态分区法

由操作系统或系统管理员预先将内存划分成若干个分区。在系统运行过程中,分区的边界不再改变。分配时,找一个空闲且足够大的分区。如没有合适的分区:①让申请者等待。②先换出某分区的内容,再将其分配出去。

1、等尺寸分区

为申请者分配指定的分区或任选一个分区。如果没有空闲分区,可将一个分区的内容换出。可能需要重定位。

会出现内部碎片,无法满足大内存的需求。

2、不等尺寸分区(固定分配、最佳适应分配)

可减少内部碎片。减少对大内存需求的限制。

①固定分配:只分配某种尺寸的特定分区,如分区已被使用,申请者必须等待。

可能出现不公平等待:虽有更大尺寸的空闲分区,却必须等待。

②最佳适应分配:分配能满足需要的最小尺寸的空闲分区,只有当所有分区都已用完时,申请者才需要等待。灵活,但可能产生较大的内部碎片。

3、静态分区:内存利用率低,产生内部碎片;尺寸和分区数量难以确定。


二、动态分区法

1、不预先确定分区的大小和数量,将分区工作推迟到实际分配内存时进行。  Lazy

初始情况下,把所有的空闲内存看成一个大分区。分配时,按申请的尺寸,找一块足够大的空闲内存分区,临时从中划出一块构成新分区。新分区的尺寸与申请的大小相等,不会出现内部碎片。回收时,尽可能与邻近的空闲分区合并。在内存紧缺时,可将某个选定的分区换出。

2、会产生外部碎片,如下图(内部碎片是指 eg:要 1M,分了 8M,产生 7M 的碎片):

3、解决外部碎片 --> 紧缩:

移动内存中的进程,将碎片集中起来,重新构成大的内存块。需要运行时的动态重定位,费时。

(1)紧缩方向:向一头紧缩,向两头紧缩。

(2)紧缩时机:①在释放分区时,如果不能与空闲分区合并,则立刻进行紧缩。

好处是不存在外部碎片,坏处是费时。

②在内存分配时,如果剩余的空闲空间总量能满足要求但没有一个独立的空闲块能满足要求,则进行紧缩。

好处是减少紧缩次数。Lazy。

4、动态分配算法:

①最先适应算法(First fit):从头开始,在满足要求的第一个空闲块中分配。

分区集中在内存的前部,大内存留在后面,便于释放后的合并。

②最佳适应算法(Best fit):遍历空闲块,在满足要求的最小空闲块中分配。

留下的碎片最小,基本无法再用,需要更频繁地紧缩。

③下一个适应算法(Next fit):从上次分配的位置开始,在满足要求的下一个空闲块中分配。

对内存的使用较平均,不容易留下大的空闲块。

④最差适应算法(Worst Fit):遍历空闲块,在满足要求的最大空闲块中分配。

留下的碎片较大,但不会剩余大内存。

最先适应算法较优,最佳适应算法较差。


三、伙伴算法 Buddy

伙伴算法:将动态分区的大小限定为 2^k  字节,分割方式限定为平分,分区就会变得较为规整,分割与合并会更容易,可以减少一些外部碎片。平分后的两块互称伙伴。

1、

分配时可能要多次平分,释放时可能要多次合并。举例:

记录大小不同的空闲页:

示意图:

2、

伙伴算法是静态分区和动态分区法的折中,比静态分区法灵活,不受分区尺寸及个数的限制;比动态分区法规范,不易出现外部碎片。会产生内部碎片,但比静态分区的小。

Linux、Windows、Ucore等都采用伙伴算法管理物理内存。

3、限定伙伴的尺寸

一般情况下,将最小尺寸定为 2^12 字节(1页,4K=4096B),最大尺寸定为1024页,11个队列。

Linux、Windows、Ucore 等都将伙伴的最小尺寸限定为1页。

4、每个页有一个管理结构

ucore 用 page,在内存初始化函数 page_init 中为系统中的每个物理页建立一个 page 结构。

页块(pageblock)是一组连续的物理页。

5、

(1)判断伙伴关系/寻找伙伴

最后两行是指,B1和B2只有第i位相反。

(2)判断伙伴是否空闲:

ucore 用 free_area[ ]数组定义空闲页块队列。

(3)确定伙伴是否在 order 队列中:

6、分配算法

7、

(1)解决内部碎片过大问题(eg:申请5页,分配8页,浪费3页):

ucore 在前部留下需要的页数,释放掉尾部各页。每次释放1页,先划分成页块,再逐个释放。

(2) 解决切分与合并过于频繁的问题:

用得较多的是单个页。位于处理器Cache中页称为热页(hot page),其余页称为冷页(cold page)。处理器对热页的访问速度要快于冷页。

可建一个热页队列(per_cpu_page),暂存刚释放的单个物理页,将合并工作向后推迟 Lazy。总是试图从热页队列中分配单个物理页。分配与释放都在热页队列的队头进行。

(3)解决内存碎化(有足够多的空闲页,但是没有大页块)问题:①将页块从一个物理位置移动到另一个物理位置,并保持移动前后逻辑地址不变(拷贝页块内容);②逻辑内存管理器。

(4)满足大内存的需求:

(5)物理内存空间都耗尽的情况:

在任何情况下,都应该预留一部分空闲的物理内存以备急需。定义两条基准线low和high,当空闲内存量小于low时,应立刻开始回收物理内存,直到空闲内存量大于high。

(6)回收物理内存:

法一:启动一个守护进程,专门用于回收物理内存。周期性启动,也可被唤醒。

法二:申请者自己去回收内存。实际是由内存分配程序回收。回收的方法很多,如释放缓冲区、页面淘汰等。


四、Slab 算法

1、

伙伴算法最小分配内存为页,对于更小的内存的管理 --> Slab 算法

内和运行过程中经常使用小内存(小于1页)eg:建立数据结构、缓冲区

内核对小内存的使用极为频繁、种类繁多、时机和数量难以预估。所以难以预先分配,只能动态地创建和撤销

2、

Slab 向伙伴算法申请大页块(批发),将其划分成小对象分配出去(零售);将回收的小对象组合成大页块后还给伙伴算法。

Slab 采用等尺寸静态分区法,将页块预先划分成一组大小相等的小块,称为内存对象。

具有相同属性的多个Slab构成一个Cache,一个Cache管理一种类型(一类应该是指一个大小)的内存对象。当需要小内存时,从预建的Cache中申请内存对象,用完之后再将其还给Cache。当Cache中缺少对象时,追加新的Slab;当物理内存紧缺时,回收完全空闲的Slab。

Slab 管理器定义的层次管理结构

Slab 算法的管理结构:

① Cache 管理结构:管理Slab,包括Slab的创建和销毁。

② Slab 管理结构:管理内存对象,包括小对象的分配与释放。

(Cache结构和Slab结构合作,共同实现内存对象的管理)

3、

(1)描述各个内存对象的使用情况

可以用位图标识空闲的内存对象。也可以将一个Slab中的空闲内存对象组织成队列,并在slab结构中记录队列的队头。

早期的Linux在每个内存对象的尾部都加入一个指针,用该指针将空闲的内存对象串联成一个真正的队列。(对象变长、不规范,空间浪费)

改进:将指针集中在一个数组中,用数组内部的链表模拟内存对象队列。

再改进:将数组中的指针换成对象序号,利用序号将空闲的内存对象串成队列。序号数组是动态创建的。

序号数组可以位于 Slab 内部,也可以位于 Slab 外部

(2)一个Cache会管理多个Slab,可以将所有Slab放在一个队列中。

Ucore为每个Cache准备了两个slab结构队列:全满的和不满的。Linux为每个Cache准备了三个slab结构队列:部分满的、完全满的和完全空闲的。

Linux允许动态创建Cache,Ucore不许。Ucore预定了对象大小,分别是32、64、128、256、512、1K、2K(4K、8K、16K、32K、64K、128K)。为每一种大小的对象预建了Cache。

(3)Slab是动态创建的,当Cache中没有空闲的内存对象时,即为其创建一个新的Slab。

Slab所需要的内存来自伙伴算法,大小是  2^page_order 个连续页。


4、小对象的尺寸

如按处理器一级缓存中缓存行(Cache Line)的大小(16、32字节)取齐,可使对象的开始位置都位于缓存行的边界处。

在将页块划分成内存对象的过程中,通常会剩余一小部分空间,位于所有内存对象之外,称为外部碎片。

Slab算法选用碎片最小的实现方案。

5、

(1)对象分配 kmalloc

① 根据size确定一个Cache。

② 如果Cache的slabs_notfull为空,则为其创建一个新的Slab。

③ 选中slabs_notfull中第一个Slab,将队头的小对象分配出去,并调整队列。

④ 对象的开始地址是:objp = slabp->s_mem + slabp->free * cachep->objsize;

(2)对象释放 kfree

① 算出对象所在的页号,找到它的 Page 结构。

② 根据 Page 找到所属的 Cache 和 Slab。

③ 算出对象序号:objnr = (objp - slabp->s_mem) / cachep->objsize;

④将序号插入Slab的free队列。

⑤整Slab所属队列。

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

推荐阅读更多精彩内容

  • 第八章 内存管理 本章通过三部分内容描述内核给自己动态分配内存: ...
    rlkbk阅读 428评论 0 1
  • Linux 内存管理 1 页的概念 linux 内核中把物理页作为内存分配的最小单位,32位CPU 页的大小通常为...
    赤兔欢阅读 3,261评论 0 5
  • 1 内存寻址 1.1 物理地址、虚拟地址以及线性地址 物理地址: 物理内存的内存单元地址 虚拟地址: 程序员看到的...
    疯狂小王子阅读 2,787评论 3 21
  • 连续分配方式,是指为一个用户程序分配一个连续的内存空间。它主要包括单一连续分配、固定分区分配和动态分区分配。 单一...
    saviochen阅读 3,547评论 0 5
  • 读《当时我就震惊了》中《努力病》一文有感。 一群五颜六色的行走发条,以为自己是超人无敌永动机,其实只是即将达到使用...
    盐柑鱼阅读 6,996评论 148 390