歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

Linux內核——內存管理

內存管理

內核把物理頁作為內存管理的基本單位;內存管理單元(MMU,管理內存並把虛擬地址轉換為物理地址)通常以頁為單位進行處理。MMU以頁大小為單位來管理系統中的頁表。從虛擬內存的角度看,頁就是最小單位。

32位系統:頁大小4KB

64位系統:頁大小8KB

在支持4KB頁大小並有1GB物理內存的機器上,物理內存會被劃分為262144個頁。內核用 struct page 結構表示系統中的每個物理頁。

struct page {

page_flags_t flags; /* 表示頁的狀態,每一位表示一種狀態*/

atomic_t _count; /* 存放頁的引用計數,0代表沒有被引用 */

atomic_t _mapcount;

unsigned long private;

strcut address_space *mapping;

pgoff_t index;

struct list_head lru;

void *virtual; /* 頁在虛擬內存中的地址,動態映射物理頁 */

}

下面,我們來解釋下其中的重要字段。

flags:這個字段用於存放頁的狀態。這些狀態包括頁是不是髒的,是不是被鎖定在內存中等。 flag 的每一位單獨表示一種狀態,所以,它至少可以同時表示出32種不同的狀態。

_count:這個字段存放頁的使用計數,也就是這個頁被引用了多少次。很奇怪,技術值變為 -1 時,就說明當前內核並沒有引用這一頁,於是,在新的分配中就可以使用它,注意,這個字段使用的是 -1 代表未使用,而不是 0 。

virtual:這個字段是頁的虛擬地址。

mapping:這個域指向和這個頁關聯的address_space 對象。

private:這個根據名字就可以看得出,它指向私有數據。

內核通過這樣的數據結構管理系統中所有的頁,因為內核需要知道一個頁是否空閒,誰有擁有這個頁。擁有者可能是:用戶空間進程、動態分配的內核數據、靜態內核代碼、頁高速緩存等等。系統中每一個物理頁都要分配這樣一個結構體,進行內存管理。

Linux基礎篇之內存管理機制 http://www.linuxidc.com/Linux/2014-03/98293.htm

Linux內存管理之高端內存 http://www.linuxidc.com/Linux/2013-06/85693.htm

Linux內存管理之分段機制 http://www.linuxidc.com/Linux/2012-11/74480.htm

Linux內存管理伙伴算法 http://www.linuxidc.com/Linux/2012-09/70711.htm

由於硬件的限制,內核並不能對所有的頁一視同仁。Linux必須處理如下兩種由於硬件存在缺陷而引起的內存尋址問題:

1)一些硬件只能用某些特定的內存地址來執行DMA(直接內存訪問)。

2)一些體系結構其內存的物理尋址范圍比虛擬尋址范圍大得多。這樣,就有一些內存不能永久地映射到內核空間上。

由於存在這種限制,內核把具有相似特性的頁劃分為不同的區(ZONE):

1)ZONE_DMA——這個區包含的頁能用來執行DMA操作。

2)ZONE_NORMAL——這個區包含的都是能正常地映射網頁。

3)ZONE_DMA32——同上,不過只能被32位設備訪問

4)ZONE_HIGHMEM——這個區包含“高端內存”,其中的頁並能不永久地映射到內核地址空間。

Linux把系統的頁劃分為區,形成不同的內存池,這樣就可以根據用途進行分配。注意,區的劃分沒有任何物理意義,這只是內核為了管理頁而采取的一種邏輯上的分組。用於DMA的內存必須從ZONE_DMA中進行分配,但是一般用途的內存卻既能從ZONE_DMA分配,也能從ZONE_NORMAL分配。

獲得頁

內核提供了一種請求內存的底層機制,並提供了對它進行訪問的幾個接口。所有這些接口都以頁為單位分配內存,定義於<linux/gfp.h>。最核心的函數是:

structpage *alloc_pages( unsigned int gfp_mask, unsigned int order );

該函數分配 2order 個連續的物理頁,並返回一個指向第一頁的 page 結構體指針,如果出錯就返回NULL。

void*page_address( struct page *page );

把給定的頁轉換成它的邏輯地址。如果無須用到 struct page,可以調用:

unsignedlong __get_free_pages( unsigned int gfp_mask, unsigned int order );

這個函數與alloc_pages 作用相同,不過它直接返回所請求的第一個頁的邏輯地址。因為頁是連續的,因此其他頁也會緊隨其後。

如果只需要一頁,可以用以下兩個函數:

structpage *alloc_page( unsigned int gfp_mask );

unsignedlong _get_free_page( unsigned int gfp_mask );

如果需要讓返回頁的內容全為0,可以使用下面這個函數

unsignedlong get_zeroed_page(unsigned int gfp_mask );

方法

描述

alloc_page(gfp_mask)

只分配一頁,返回指向頁結構的指針

alloc_pages(gfp_mask, order)

分配 2^order 個頁,返回指向第一頁頁結構的指針

__get_free_page(gfp_mask)

只分配一頁,返回指向其邏輯地址的指針

__get_free_pages(gfp_mask, order)

分配 2^order 個頁,返回指向第一頁邏輯地址的指針

get_zeroed_page(gfp_mask)

只分配一頁,讓其內容填充為0,返回指向其邏輯地址的指針

當不再需要頁時可以使用以下函數來釋放它。

void__free_pages( struct page *page, unsigned int order );

voidfree_pages( unsigned long addr, unsigned int order );

voidfree_page( unsigned long addr );

釋放頁時要謹慎,只能釋放屬於你的頁。傳遞了錯誤的 struct page 或地址,用了錯誤的 order 值都可能導致系統崩潰。請記住,內核是完全依賴自己的。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-08/105365p2.htm

Copyright © Linux教程網 All Rights Reserved