linux 下的csp 模块,linux kernel 中MIGRATE_TYPES的理解
在2.6.24之前的內(nèi)核版本中,free_area結(jié)構(gòu)中只有一個(gè)free_list數(shù)組,而從2.6.24開(kāi)始,free_area結(jié)構(gòu)中存有MIGRATE_TYPES個(gè)free_list,這些數(shù)組是根據(jù)頁(yè)框的移動(dòng)性來(lái)劃分的,為什么要進(jìn)行這樣的劃分呢?實(shí)際上也是為了減少碎片而提出的,我們考慮下面的情況:
圖中一共有32個(gè)頁(yè),只分配出了4個(gè)頁(yè)框,但是能夠分配的最大連續(xù)內(nèi)存也只有8個(gè)頁(yè)框(因?yàn)榛锇橄到y(tǒng)分配出去的內(nèi)存必須是2的整數(shù)次冪個(gè)頁(yè)框),內(nèi)核解決這種問(wèn)題的辦法就是將不同類型的頁(yè)進(jìn)行分組。分配出去的頁(yè)面可分為三種類型:
不可移動(dòng)頁(yè)(Non-movable pages):這類頁(yè)在內(nèi)存當(dāng)中有固定的位置,不能移動(dòng)。內(nèi)核的核心分配的內(nèi)存大多屬于這種類型
可回收頁(yè)(Reclaimable pages):這類頁(yè)不能直接移動(dòng),但可以刪除,其內(nèi)容頁(yè)可以從其他地方重新生成,例如,映射自文件的數(shù)據(jù)屬于這種類型,針對(duì)這種頁(yè),內(nèi)核有專門的頁(yè)面回收處理
可移動(dòng)頁(yè)(Movable pages):這類頁(yè)可以隨意移動(dòng),用戶空間應(yīng)用程序所用到的頁(yè)屬于該類別。它們通過(guò)頁(yè)表來(lái)映射,如果他們復(fù)制到新的位置,頁(yè)表項(xiàng)也會(huì)相應(yīng)的更新,應(yīng)用程序不會(huì)注意到任何改變。
假如上圖中大部分頁(yè)都是可移動(dòng)頁(yè),而分配出去的四個(gè)頁(yè)都是不可移動(dòng)頁(yè),由于不可移動(dòng)頁(yè)插在了其他類型頁(yè)的中間,就導(dǎo)致了無(wú)法從原本空閑的連續(xù)內(nèi)存區(qū)中分配較大的內(nèi)存塊。考慮下圖的情況:
將可回收頁(yè)和不可移動(dòng)頁(yè)分開(kāi),這樣雖然在不可移動(dòng)頁(yè)的區(qū)域當(dāng)中無(wú)法分配大塊的連續(xù)內(nèi)存,但是可回收頁(yè)的區(qū)域卻沒(méi)有受其影響,可以分配大塊的連續(xù)內(nèi)存。
內(nèi)核對(duì)于遷移類型的定義如下:
[cpp]
#define MIGRATE_UNMOVABLE ? ? 0
#define MIGRATE_RECLAIMABLE ? 1
#define MIGRATE_MOVABLE ? ? ? 2
#define MIGRATE_PCPTYPES ? ? ?3 /* the number of types on the pcp lists */
#define MIGRATE_RESERVE ? ? ? 3
#define MIGRATE_ISOLATE ? ? ? 4 /* can't allocate from here */
#define MIGRATE_TYPES ? ? ? ? 5
前三種類型已經(jīng)介紹過(guò)
MIGRATE_PCPTYPES是per_cpu_pageset,即用來(lái)表示每CPU頁(yè)框高速緩存的數(shù)據(jù)結(jié)構(gòu)中的鏈表的遷移類型數(shù)目
MIGRATE_RESERVE是在前三種的列表中都沒(méi)用可滿足分配的內(nèi)存塊時(shí),就可以從MIGRATE_RESERVE分配
MIGRATE_ISOLATE用于跨越NUMA節(jié)點(diǎn)移動(dòng)物理內(nèi)存頁(yè),在大型系統(tǒng)上,它有益于將物理內(nèi)存頁(yè)移動(dòng)到接近于是用該頁(yè)最頻繁地CPU
MIGRATE_TYPES表示遷移類型的數(shù)目
當(dāng)一個(gè)指定的遷移類型所對(duì)應(yīng)的鏈表中沒(méi)有空閑塊時(shí),將會(huì)按以下定義的順序到其他遷移類型的鏈表中尋找:
static int fallbacks[MIGRATE_TYPES][MIGRATE_TYPES-1] = {
[MIGRATE_UNMOVABLE] ? = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, ? MIGRATE_RESERVE },
[MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, ? MIGRATE_MOVABLE, ? MIGRATE_RESERVE },
[MIGRATE_MOVABLE] ? ? = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },
[MIGRATE_RESERVE] ? ? = { MIGRATE_RESERVE, ? ? MIGRATE_RESERVE, ? MIGRATE_RESERVE }, /* Never used */
};
(三)?linux內(nèi)核對(duì)伙伴系統(tǒng)的改進(jìn)--migrate_type
linux底層使用伙伴系統(tǒng)-buddy管理物理內(nèi)存,buddy可以被證明是一種很有效的內(nèi)存管理方式,但是它也擁有很多缺點(diǎn),其中碎片避免的不完備性 --僅僅寄托于釋放時(shí)的合并操作而不考慮分配時(shí)的策略,這也許是它最大的不足,linux2.6內(nèi)核的后期版本對(duì)這個(gè)問(wèn)題進(jìn)行了改進(jìn),大大避免了碎片的泛 濫。在linux中,buddy是通過(guò)下列數(shù)據(jù)結(jié)構(gòu)表示的(2.6的早期內(nèi)核):
struct free_area {
struct list_head??? free_list;
unsigned long??? ??? *map;
};
系統(tǒng)中10個(gè)free_area組成一個(gè)數(shù)組,每一個(gè)free_area包含一個(gè)鏈表,每一個(gè)鏈表上鏈接有空閑內(nèi)存頁(yè)面塊。后來(lái)引入了MIGRATE_TYPE,于是free_area結(jié)構(gòu)體就成了:
struct free_area {
struct list_head??? free_list[MIGRATE_TYPES];
unsigned long??? ??? nr_free;
};
每一個(gè)free_area包含多個(gè)鏈表,其中每一個(gè)鏈表中的內(nèi)存頁(yè)面按照其自身是否可以釋放或者遷移被歸為一類,于是凡是請(qǐng)求“不可遷移”頁(yè)面的分配請(qǐng)求 全部在free_list[MIGRATE_UNMOVABLE]這條鏈表上分配,和老版本一樣,系統(tǒng)中有10個(gè)free_area代表大小為2的N次冪 個(gè)不同頁(yè)面的集合。這種歸類可以最小化內(nèi)存碎片。
buddy系統(tǒng)本身就有效的防止了碎片,然而還不夠。
buddy主要體現(xiàn)在:1.互為buddy的頁(yè)面塊不可能共存于一個(gè)free_area鏈表,它們總是傾向于合并;2.一個(gè)free_area的鏈表中的 頁(yè)面order相同,但是它們肯定彼此不互為buddy,這些頁(yè)面用于該order大小需求的頁(yè)面分配。但是buddy的碎片防止機(jī)制寄托于內(nèi)存使用者會(huì) 及時(shí)釋放掉內(nèi)存的情況,如果使用者長(zhǎng)期不釋放內(nèi)存,或者說(shuō)在使用者還沒(méi)有釋放內(nèi)存的這一段時(shí)間期間,碎片將是存在的,并且可能還會(huì)導(dǎo)致很大的問(wèn)題,比如在 物理內(nèi)存中間分配了一頁(yè)面,然而僅因?yàn)榉峙涞倪@一個(gè)頁(yè)面不可移動(dòng),在它被釋放之前,系統(tǒng)可用的最大的連續(xù)物理內(nèi)存就只有不到一半物理內(nèi)存總大小了。究其根 源,這種問(wèn)題的根源在于buddy系統(tǒng)僅僅釋放頁(yè)面時(shí)的合并操作防止了碎片的產(chǎn)生,不管頁(yè)面從哪里被分配,只要它能有效被釋放,碎片就是可以避免的,也就 是說(shuō),buddy系統(tǒng)對(duì)于分配并沒(méi)有更多的約束,僅僅滿足在10個(gè)free_area中從小到大的順序掃描即可。
既然找到了buddy的問(wèn)題,那么只要對(duì)分配動(dòng)作采取一定的約束,碎片就可以進(jìn)一步避免了。
最簡(jiǎn)單而又不引入過(guò)多復(fù)雜性的辦法就是將頁(yè)面按照“可移動(dòng)”屬性分類,將不可移動(dòng)的頁(yè)面分為一類,將可以移動(dòng)的頁(yè)面分為一類,它們各自占據(jù)一塊足夠大的連 續(xù)物理空間,不可移動(dòng)的頁(yè)面分配需求則盡量在它自己的頁(yè)面類中分配,可移動(dòng)的頁(yè)面也一樣,這樣一來(lái),不可移動(dòng)的頁(yè)面的不可移動(dòng)性僅僅影響它自身的類別而不 會(huì)導(dǎo)致一個(gè)不可移動(dòng)的頁(yè)面兩邊都是可移動(dòng)的頁(yè)面。這就是MIGRATE_TYPE被引入的目的。MIGRATE_TYPE限制了內(nèi)存頁(yè)面的分配地點(diǎn)從而避 免碎片,而不再僅僅寄希望于它們被釋放時(shí)通過(guò)合并避免碎片。
可以說(shuō)MIGRATE_TYPE僅僅是一種防止碎片的策略,不應(yīng)該因?yàn)樗拇嬖诙绊懙絻?nèi)存分配的結(jié)果,也就是說(shuō),如果在一個(gè)MIGRATE_TYPE鏈 表中沒(méi)有內(nèi)存可以分配了,那么也還是可以從別的鏈表中“暫時(shí)搶”一些的。另外,還有一個(gè)問(wèn)題,內(nèi)核載初始化的時(shí)候如何為“不可移動(dòng)類”或者“可移動(dòng)類”頁(yè) 面指定初始大小呢?也就是說(shuō),一開(kāi)始,系統(tǒng)的free_area中的這些類別鏈表的頁(yè)面各該是多少個(gè)呢?事實(shí)上,內(nèi)核從來(lái)沒(méi)有指定過(guò)初始大小,而是一開(kāi)始 將所有頁(yè)面都?xì)w到“可移動(dòng)”組當(dāng)中,而別的組全部都是空的,等到真的有不可移動(dòng)頁(yè)面需求的時(shí)候再?gòu)目梢苿?dòng)組中撥一批給不可移動(dòng)組鏈表,想一下這也是合理 的,畢竟只是一些“不可移動(dòng)”的頁(yè)面造成了內(nèi)存的長(zhǎng)期碎片化,如果沒(méi)有這些長(zhǎng)期使用的不可移動(dòng)頁(yè)面,碎片的問(wèn)題是不大的。這個(gè)從 __rmqueue_fallback函數(shù)中可以看出,系統(tǒng)的內(nèi)存子系統(tǒng)擁有一個(gè)fallbacks序列,該序列展示了一個(gè)分配序列,也就是如果一個(gè) migratetype鏈表中如果分配不到內(nèi)存的話,下一個(gè)應(yīng)該在哪個(gè)migratetype鏈表中分配。從__rmqueue_fallback可以看 出,如果從要求的migratetype空閑鏈表中分配不到內(nèi)存的話,并不是在根據(jù)fallbacks序列在“下一個(gè)”鏈表中僅僅分配到自己本次所需的就 完事了,而是一次性從fallbacks序列中指示的鏈表中轉(zhuǎn)移足夠多的頁(yè)面到分配時(shí)要求的migratetype鏈表,畢竟該種類型的空閑鏈表已經(jīng)沒(méi)有 頁(yè)面了,確實(shí)需要補(bǔ)充了,并且如果補(bǔ)充的頁(yè)面太少,那么就會(huì)給轉(zhuǎn)移的源migratetype類型組造成碎片,只有一次性分配一大塊內(nèi)存,才不至于引入碎 片。
static struct page *__rmqueue_fallback(struct zone *zone, int order,
int start_migratetype)
{
struct free_area * area;
int current_order;
struct page *page;
int migratetype, i;
//盡量一次性撥出盡可能多的內(nèi)存頁(yè)面給“該”migratetype的free_area鏈表
for (current_order = MAX_ORDER-1; current_order >= order; --current_order) {
for (i = 0; i < MIGRATE_TYPES - 1; i++) {
migratetype = fallbacks[start_migratetype][i];
if (migratetype == MIGRATE_RESERVE)? //不允許占用保留內(nèi)存
continue;
area = &(zone->free_area[current_order]);
if (list_empty(&area->free_list[migratetype]))
continue;
page = list_entry(area->free_list[migratetype].next, struct page, lru);
area->nr_free--;
...
list_del(&page->lru);
rmv_page_order(page);
__mod_zone_page_state(zone, NR_FREE_PAGES, -(1UL << order));
if (current_order == pageblock_order)
set_pageblock_migratetype(page,??? start_migratetype);
//將除去本次自己要用的page[order]之外的其它頁(yè)面全部補(bǔ)充進(jìn)該area的migratetype空閑鏈表
expand(zone, page, order, current_order, area, migratetype);
return page;
}
}
return __rmqueue_smallest(zone, order, MIGRATE_RESERVE);
}
另外,還有一種類似的機(jī)制用于避免碎片,那就是使用ZONE的概念,新構(gòu)造出一個(gè)虛擬的ZONE--ZONE_MOVABLE,所謂的虛擬就是它并不和任 何物理內(nèi)存區(qū)間相關(guān)聯(lián),而是可以附著在任何的物理zone上,用戶可以通過(guò)命令行參數(shù)指定用于“可移動(dòng)”或者“不可移動(dòng)”的內(nèi)存的大小,從而也就規(guī)定了虛 擬的ZONE_MOVABLE的大小。一般的最終比較高的物理內(nèi)存區(qū)域用于可移動(dòng)的虛擬zone(ZONE_MOVABLE)分配,這是因?yàn)榈偷刂穬?nèi)存更 多的用于dma或者isa或者內(nèi)核數(shù)據(jù)結(jié)構(gòu)(一一線性映射)等,而高內(nèi)存則一般用于用戶進(jìn)程(可以交換到交換空間...)
總結(jié)
以上是生活随笔為你收集整理的linux 下的csp 模块,linux kernel 中MIGRATE_TYPES的理解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: [2] ADB 基本用法
- 下一篇: 计算机控制作业及答案,《微机系统与维护》