linux內核源碼剖析 博客,【Linux內存源碼分析】頁面遷移

頁面遷移其實是伙伴管理算法中的一部分,鑒于其特殊性,特地另行分析。它是2007年的時候,2.6.24內核版本開發時,新增碎片減少策略(the fragmentation reduction strategy)所引入的。該策略也稱之為反碎片技術(anti-gragmentation)。

根據《深入linux內核架構》的描述,反碎片的由來是因為Linux內存管理長期存在一個問題:系統啟動并長期運行后,物理內存將會產生很多碎片。暫且假設內存頁面數為60,則長期運行后,其頁面的使用情況可能將會如下圖(灰色為已分配)。

8888023d03eb39f029d0eee528bd6a82.png

雖然其未被分配的頁面仍有25%,但能夠申請到的最大頁面僅為一頁。不過這對用戶空間是沒有影響的,主要是由于用戶態的內存是通過頁面映射而得到的。所以不在乎具體的物理頁面分布,其仍是可以將其映射為連續的一塊內存提供給用戶態程序使用。于是用戶態可以感知的內存則如下。

6e58c463a7b5316cb5d91fd73bdcf3e4.png

但是對于內核態,碎片則是個嚴肅的問題,因為大部分物理內存都直接映射到內核的永久映射區里面。如果真的存在碎片,將真的如第一張圖所示,無法映射到比一頁更大的內存,這長期是linux的短板之一。于是為了解決該問題,則引入了反碎片。

linux內核在內存管理時,將已分配的頁面劃分為三種類型:

不可移動頁

——該類型頁面在內存中位置固定,不可移動。內核核心大部分內存屬于該類型;

可回收頁

——不能夠直接移動,但是可以刪除,而內容則可以從某些源重新生成。如文件數據映射的頁面則歸屬此類;

可移動頁

——可以隨意移動,分配給用戶態程序運行的用戶空間頁面則為該類。由于是通過頁面映射而得,將其復制到新位置后,更新映射表項,重新映射,應用程序是不感知的。

頁面的可遷移性則取決于它屬于哪一類。而內核使用的反碎片技術則是基于將具有相同可移動性的頁分組的思想來實現的。當出現碎片的情況時,可移動頁面將會遷移,將為申請者騰出所需的連續頁面空間,由此避免了空閑頁面空間過于零碎而無法申請到大塊連續內存。也由此,不可移動頁面不允許在可移動頁面中申請,避免因不可遷移而導致碎片。

其中具體遷移類型在頭文件include/linux/mmzone.h中定義了:

【file:/include/linux/mmzone.h】

enum {

MIGRATE_UNMOVABLE,

MIGRATE_RECLAIMABLE,

MIGRATE_MOVABLE,

MIGRATE_PCPTYPES,/* the number of types on the pcp lists */

MIGRATE_RESERVE = MIGRATE_PCPTYPES,

#ifdef CONFIG_CMA

/*

* MIGRATE_CMA migration type is designed to mimic the way

* ZONE_MOVABLE works. Only movable pages can be allocated

* from MIGRATE_CMA pageblocks and page allocator never

* implicitly change migration type of MIGRATE_CMA pageblock.

*

* The way to use it is to change migratetype of a range of

* pageblocks to MIGRATE_CMA which can be done by

* __free_pageblock_cma() function. What is important though

* is that a range of pageblocks must be aligned to

* MAX_ORDER_NR_PAGES should biggest page be bigger then

* a single pageblock.

*/

MIGRATE_CMA,

#endif

#ifdef CONFIG_MEMORY_ISOLATION

MIGRATE_ISOLATE,/* can't allocate from here */

#endif

MIGRATE_TYPES

};

各類型的說明則為:

MIGRATE_UNMOVABLE

——在內存當中有固定的位置,不能移動。內核的核心分配的內存大多屬于這種類型;

MIGRATE_RECLAIMABLE

——不能直接移動,但可以刪除,其內容頁可以從其他地方重新生成,例如,映射自文件的數據屬于這種類型,針對這種頁,內核有專門的頁面回收處理;

MIGRATE_MOVABLE

——可以隨意移動,用戶空間應用程序所用到的頁屬于該類別。它們通過頁表來映射,如果他們復制到新的位置,頁表項也會相應的更新,應用程序不會注意到任何改變;

MIGRATE_PCPTYPES

——是per_cpu_pageset,即用來表示每CPU頁框高速緩存的數據結構中的鏈表的遷移類型數目;

MIGRATE_RESERVE

——保留頁,是在前三種的列表中都沒用可滿足分配的內存塊時,就可以從MIGRATE_RESERVE分配;

MIGRATE_CMA

——連續內存分配,用于避免預留大塊內存導致系統可用內存減少而實現的,即當驅動不使用內存時,將其分配給用戶使用,而需要時則通過回收或者遷移的方式將內存騰出來。

MIGRATE_ISOLATE

——用于跨越NUMA節點移動物理內存頁,該索引的頁不能分配,在大型系統上,它有益于將物理內存頁移動到接近于是用該頁最頻繁地CPU;

MIGRATE_TYPES

——表示遷移類型的數目。

至于遷移類型的頁面管理實際上采用的還是伙伴管理算法的管理方式,內存管理區zone的結構里面的free_area是用于管理各階內存頁面,而其里面的free_list則是對各遷移類型進行區分的鏈表。回顧內存頁面釋放的函數__free_pages,其將空閑頁面掛回去的時候,是做了遷移類型區分的。也就是意味著頁面遷移類型是伴隨著伙伴管理算法的內存管理構建,根據遷移類型進行分而治之初始化。

那么各種遷移類型的頁面分配是如何運轉的?

頁面分配函數入口__alloc_pages():

【file:/include/linux/gfp.h】

static inline struct page *

__alloc_pages(gfp_t gfp_mask, unsigned int order,

struct zonelist *zonelist)

{

return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);

}

其首入參在__alloc_pages_nodemask()里面會經過allocflags_to_migratetype(gfp_mask)轉換獲取到申請頁面的類型。該遷移類型會在其內部調用函數__rmqueue()中使用。

【file:/mm/page_alloc.c】

/*

* Do the hard work of removing an element from the buddy allocator.

* Call me with the zone->lock already held.

*/

static struct page *__rmqueue(struct zone *zone, unsigned int order,

int migratetype)

{

struct page *page;

retry_reserve:

page = __rmqueue_smallest(zone, order, migratetype);

if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {

page = __rmqueue_fallback(zone, order, migratetype);

/*

* Use MIGRATE_RESERVE rather than fail an allocation. goto

* is used because __rmqueue_smallest is an inline function

* and we want just one call site

*/

if (!page) {

migratetype = MIGRATE_RESERVE;

goto retry_reserve;

}

}

trace_mm_page_alloc_zone_locked(page, order, migratetype);

return page;

}

前面分析可以知道__rmqueue_smallest()僅是在指定遷移類型下自底向上進行各階遍歷查找所需的空閑頁面,而據上代碼其如果在指定遷移類型下分配失敗,且類型不為MIGRATE_RESERVE時,將會調用__rmqueue_fallback()進行分配。

接下來看一下__rmqueue_fallback()實現:

【file:/mm/page_alloc.c】

/* Remove an element from the buddy allocator from the fallback list */

static inline struct page *

__rmqueue_fallback(struct zone *zone, int order, int start_migratetype)

{

struct free_area *area;

int current_order;

struct page *page;

int migratetype, new_type, i;

/* Find the largest possible block of pages in the other list */

for (current_order = MAX_ORDER-1; current_order >= order;

--current_order) {

for (i = 0;; i++) {

migratetype = fallbacks[start_migratetype][i];

/* MIGRATE_RESERVE handled later if necessary */

if (migratetype == MIGRATE_RESERVE)

break;

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--;

new_type = try_to_steal_freepages(zone, page,

start_migratetype,

migratetype);

/* Remove the page from the freelists */

list_del(&page->lru);

rmv_page_order(page);

expand(zone, page, order, current_order, area,

new_type);

trace_mm_page_alloc_extfrag(page, order, current_order,

start_migratetype, migratetype, new_type);

return page;

}

}

return NULL;

}

可以看到其異于通常的伙伴管理算法,內存頁面是由最高階開始進行查找的,而查找的遷移類型是根據fallbacks備選類型中進行遍歷獲得并止于MIGRATE_RESERVE類型。由此獲得的階號和遷移類型查找zone->free_area[]->free_list[]空閑頁面管理鏈表,如果查找到的話,則將其摘除,否則進入下一類型查找,最后所有類型都查找不到的時候,才會降階查找。

其中fallbacks[][]是已確定的類型順序結構,其定義為:

【file:/mm/page_alloc.c】

/*

* This array describes the order lists are fallen back to when

* the free lists for the desirable migrate type are depleted

*/

static int fallbacks[MIGRATE_TYPES][4] = {

[MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE },

[MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE },

#ifdef CONFIG_CMA

[MIGRATE_MOVABLE] = { MIGRATE_CMA, MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },

[MIGRATE_CMA] = { MIGRATE_RESERVE }, /* Never used */

#else

[MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },

#endif

[MIGRATE_RESERVE] = { MIGRATE_RESERVE }, /* Never used */

#ifdef CONFIG_MEMORY_ISOLATION

[MIGRATE_ISOLATE] = { MIGRATE_RESERVE }, /* Never used */

#endif

};

具體分析一下try_to_steal_freepages()函數實現:

【file:/mm/page_alloc.c】

/*

* If breaking a large block of pages, move all free pages to the preferred

* allocation list. If falling back for a reclaimable kernel allocation, be

* more aggressive about taking ownership of free pages.

*

* On the other hand, never change migration type of MIGRATE_CMA pageblocks

* nor move CMA pages to different free lists. We don't want unmovable pages

* to be allocated from MIGRATE_CMA areas.

*

* Returns the new migratetype of the pageblock (or the same old migratetype

* if it was unchanged).

*/

static int try_to_steal_freepages(struct zone *zone, struct page *page,

int start_type, int fallback_type)

{

int current_order = page_order(page);

/*

* When borrowing from MIGRATE_CMA, we need to release the excess

* buddy pages to CMA itself.

*/

if (is_migrate_cma(fallback_type))

return fallback_type;

/* Take ownership for orders >= pageblock_order */

if (current_order >= pageblock_order) {

change_pageblock_range(page, current_order, start_type);

return start_type;

}

if (current_order >= pageblock_order / 2 ||

start_type == MIGRATE_RECLAIMABLE ||

page_group_by_mobility_disabled) {

int pages;

pages = move_freepages_block(zone, page, start_type);

/* Claim the whole block if over half of it is free */

if (pages >= (1 << (pageblock_order-1)) ||

page_group_by_mobility_disabled) {

set_pageblock_migratetype(page, start_type);

return start_type;

}

}

return fallback_type;

}

該函數主要實現了內存頁面的遷移類型的變更,將__rmqueue_fallback()查找到滿足需要的內存頁面空間類型轉為申請的類型。其中MIGRATE_CMA類型不做類型轉換,此外類型轉換的頁面數量為pageblock_nr_pages為單位的倍數,還有就是對于階較低的內存頁面(小于pageblock_order/2)、類型不為MIGRATE_RECLAIMABLE且未開啟頁面遷移的情況下,是不做類型轉換的。完了,在__rmqueue_fallback()里面根據其轉換后的類型通過expand()擴展到對應的遷移類型伙伴管理系統中。

小結一下,__rmqueue_fallback()是自高往低階遍歷fallbacks遷移類型表,查找滿足分配需要的內存頁面,然后將查找到的內存頁面進行類型變更后合并到所申請的類型中,以實現類型遷移。值得注意的是,之所以內存遷移都是以內存塊的高階進行的,主要就是為了反碎片化,避免當前類型無法滿足需要的時候,過于頻繁地向備選類型進行小片內存申請和做遷移而導致備選類型的內存頁面產生大量水平,將問題控制在所申請的內存類型中。

最后看一下set_pageblock_migratetype()的實現:

【file:/mm/page_alloc.c】

/**

* set_pageblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages

* @page: The page within the block of interest

* @start_bitidx: The first bit of interest

* @end_bitidx: The last bit of interest

* @flags: The flags to set

*/

void set_pageblock_flags_mask(struct page *page, unsigned long flags,

unsigned long end_bitidx,

unsigned long mask)

{

struct zone *zone;

unsigned long *bitmap;

unsigned long pfn, bitidx, word_bitidx;

unsigned long old_word, word;

BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4);

zone = page_zone(page);

pfn = page_to_pfn(page);

bitmap = get_pageblock_bitmap(zone, pfn);

bitidx = pfn_to_bitidx(zone, pfn);

word_bitidx = bitidx / BITS_PER_LONG;

bitidx &= (BITS_PER_LONG-1);

VM_BUG_ON_PAGE(!zone_spans_pfn(zone, pfn), page);

bitidx += end_bitidx;

mask <<= (BITS_PER_LONG - bitidx - 1);

flags <<= (BITS_PER_LONG - bitidx - 1);

word = ACCESS_ONCE(bitmap[word_bitidx]);

for (;;) {

old_word = cmpxchg(&bitmap[word_bitidx], word, (word & ~mask) | flags);

if (word == old_word)

break;

word = old_word;

}

}

其中get_pageblock_bitmap()用于取得zone結構體中pageblock_flags成員,而后面則是基于此做位圖操作。通過該函數,可以看到內存頁面的類型管理是通過其所屬的zone的結構體中的pageblock_flags所管理的位圖進行標識該頁面的遷移類型。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281607.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281607.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281607.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

360的下一代SOC是這個樣子的

幾乎所有大型企業或機構的IT系統中&#xff0c;都會有安全運營中心(SOC)&#xff0c;它是網絡安全防護體系從設備部署到系統建設&#xff0c;再到統一管理&#xff0c;這一發展過程的自然產物。但在國內的實際應用中&#xff0c;SOC的問題多多。 首先是數據類型不全&#xff0c…

【轉載】利用scipy.misc等庫對jpg以及png等圖像數據預處理(用于深度學習喂數據)...

http://blog.csdn.net/qq_16949707/article/details/56306720 轉載于:https://www.cnblogs.com/tenderwx/p/8057599.html

2018年下半年網絡公式考試案例分析真題

閱讀以下說明&#xff0c;回答問題1至問題3&#xff0c;將解答填入答題紙對應的解答欄內。【說明】某公司網絡劃分為兩個子網&#xff0c;其中設備A是DHCP服務器&#xff0c;如圖3-1所示。 【問題1】(6分&#xff0c;每空2分)DHCP在分配IP地址時使用 (1) 的方式&#xff0c; 而…

哪一個不是linux常用的shell,Linux下查看使用的是哪種shell的方法匯總

查看當前發行版可以使用的shell復制代碼代碼如下:[rootlocalhost ~]$ cat /etc/shells/bin/sh/bin/bash/sbin/nologin查看當前使用的shell方法一、最常用的查看shell的命令&#xff0c;但不能實時反映當前shell復制代碼代碼如下:[rootlocalhost ~]$ echo $SHELL/bin/bash二、下…

企業建設呼叫中心需要考慮哪些因素

呼叫中心發展至今&#xff0c;它的意義早已不是90年代末,只是簡單地解決客戶客服系統的要求。現在的呼叫中心有了新的使命&#xff0c;比如拓展成為一個信息服務中心&#xff0c;或者成為一個營銷中心。客戶如何能通過這樣的手段&#xff0c;使企業與其他的企業之間形成差異化的…

【單片機入門】(三)應用層軟件開發的單片機學習之路-----UART串口通訊和c#交互...

本文由網友投稿。作者&#xff1a;陳顯達原文標題&#xff1a;【單片機入門】(三)應用層軟件開發的單片機學習之路-----UART串口通訊和c#交互原文鏈接&#xff1a;https://www.cnblogs.com/1996-Chinese-Chen/p/16826558.html引言在第一章博客中&#xff0c;我們講了Arduino對E…

linux中使用yum的優點,linux – 自動“yum update”以保證服務器安全 – 優點和缺點?...

這取決于根據我使用CentOS的經驗,它非常安全,因為您只使用CentOS基本存儲庫.您是否應該偶爾嘗試更新失敗…是…在您應該期望出現故障的硬盤驅動器或偶爾出現故障的CPU的同一級別上.您永遠不會有太多備份. &#x1f642;關于自動更新的好處是,您可以比手動修補更快(因此更安全).…

高能力成熟度軟件企業中軟件質量工程師的職責

隨著科學技術的不斷發展進步&#xff0c;企業之間的競爭越來越激烈。軟件企業要想在競爭中發展生存&#xff0c;提高軟件產品質量已成為必要條件。在一些高能力成熟度軟件企業中&#xff0c;專門成立了質量保證和控制職能部門&#xff0c;起著提高項目管理透明性和確保軟件產品…

存儲過程和函數的區別

存儲過程和函數的區別存儲過程和函數目的是為了 可重復地 執行操作數據庫的sql語句的集合。區別是寫法和調用上。寫法上&#xff1a;存儲過程的參數列表可以有輸入參數、輸出參數、可輸入輸出的參數&#xff1b;函數的參數列表只有輸入參數&#xff0c;并且有return <返回值…

機器學習案例丨基于廣泛和深入的推薦 - 餐廳評級預測

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;18分鐘&#xff09;Microsoft Azure Machine Learning Studio 是微軟強大的機器學習平臺&#xff0c;在設計器中&#xff0c;微軟內置了15個場景案例&#xff0c;但網上似乎沒有對這15個案例深度刨析的分析資料&#…

css linux 等寬字體,比例字體等寬字體

我們都知道等寬字體和比例字體的區別&#xff0c;就在于比例字體(Monospaced Font)即每個字母寬度是按一定比例自動調整的&#xff0c;而等寬字體(Proportional font)則是固定寬度&#xff0c;固定間距&#xff0c;字體的每一個字母和字符所占的水平空間都是相同的。比例字體&a…

三星智能家居系統頻繁故障 大批用戶受到影響

Shelley Powers正在她密蘇里州郊區的房子中鼾睡&#xff0c;突然警鈴大作將她驚醒&#xff0c;在仔細排查之后&#xff0c;發現是虛驚一場&#xff0c;是安全傳感器誤報。在此之后的幾周&#xff0c;她的三星Smart Things智能家居系統頻繁出現故障&#xff0c;比如設定的燈具不…

適用于 .NET 的開源文本差異對比組件

你好&#xff0c;這里是 Dotnet 工具箱&#xff0c;定期分享 Dotnet 有趣&#xff0c;實用的工具或組件&#xff0c;希望對您有用&#xff01;簡介對于開發人員來說&#xff0c;Git 是我們經常使用的工具&#xff0c;在每次編寫完代碼并提交后&#xff0c;我們可以通過 git dif…

MySQL—查詢某時間范圍的數據

-- 查詢今天的數據 select * from user where to_days(birthday) to_days(CURDATE()); -- 查詢昨天的數據 select * from user where to_days(CURDATE()) - to_days(birthday)<1; -- 查詢最近7天的數據 select * from user where birthday > DATE_SUB(CURDATE(),INTERVA…

box-shadow陰影合集

2019獨角獸企業重金招聘Python工程師標準>>> * box-shadow可以設置6個值。其中4個可選&#xff1b;2個必須指定&#xff1a;分別是x軸偏移量和y軸偏移量&#xff0c;這2個值可以是正值&#xff0c;可以是負值&#xff0c;也可以是0&#xff0c;但不可以省略不寫 陰影…

《數據科學R語言實踐:面向計算推理與問題求解的案例研究法》一一2.5 為跨年度的個人參賽選手構造記錄...

本節書摘來自華章計算機《數據科學R語言實踐&#xff1a;面向計算推理與問題求解的案例研究法》一書中的第2章&#xff0c;第2.5節,作者&#xff1a;[美] 德博拉諾蘭&#xff08;Deborah Nolan&#xff09;  鄧肯坦普朗&#xff08;Duncan Temple Lang&#xff09;  更多章…

基于 abp 微服務架構的開源低代碼平臺

你好&#xff0c;這里是 Dotnet 工具箱&#xff0c;定期分享 Dotnet 有趣&#xff0c;實用的工具或組件&#xff0c;希望對您有用&#xff01;簡介 ABP-MicroService是 一個基于ABP vNext微服務架構、vue-element-admin的后臺管理框架&#xff0c;適用于大型分布式業務系統和企…

linux android sdk gengxinman,Android 實現增量更新

一、概述增量更新相較于全量更新的好處不言而喻&#xff0c;利用差分算法獲得1.0版本到2.0版本的差分包&#xff0c;這樣在安裝了1.0的設備上只要下載這個差分包就能夠完成由1.0-2.0的更新。比如&#xff1a;存在一個1.0版本的apkapk1.png然后需要升級到2.0版本&#xff0c;而2…

(轉)yi_meng linux 下 ifcfg-eth0 配置 以及ifconfig、ifup、ifdown區別

linux 下 ifcfg-eth0 配置 以及ifconfig、ifup、ifdown區別 原文&#xff1a;https://www.cnblogs.com/yi-meng/p/3214471.html這3個命令的用途都是啟動網絡接口&#xff0c;不過&#xff0c;ifup與ifdown僅就 /etc/sysconfig/network- scripts內的ifcfg-ethx&#xff08;x為數…

Pycharm上Django的使用 Day8

2019獨角獸企業重金招聘Python工程師標準>>> 1.添加新條目 1>編寫用于添加新條目的表單 在forms.py中創建一個與模型Entry相關聯的表單 1處給字段text指定一個空標簽 2處定義小部件widgets,widgets是一個HTML表單元素 2>定義new_entry的URL模式 在用于添加新條…