Linux記憶體管理之高階記憶體對映

2021-05-26 02:01:21 字數 3719 閱讀 5232

分析完linux記憶體管理的基本概念與實現之後,就可以接著分析使用者空間與核心空間的互動操作了。brk系統呼叫屬於那種常用但是「可見度」不高的操作,常用於使用者空間堆的管理(請參閱本站的《中的malloc機制分析》一文)。

brk在使用者空間的介面為int brk(void *end_data_segment)。它通過系統呼叫進入核心空間。在核心的相應介面為sys_brk().

閒言少敘,言歸正傳。轉入相應的**。同以往一樣,linux核心**版本為2.6.21

//sys_brk:

用來擴大或者縮小程序的資料段邊界,brk為新的資料段邊界).

asmlinkage unsigned long sys_brk(unsigned long brk)

//執行到這裡的話,說明要執行的是資料段的伸展操作

//不能超過資料段上限

rlim = current->rlim[rlimit_data].rlim_cur;

if (rlim < rlim_infinity && brk - mm->start_data > rlim)

goto out;

//伸展空間已經有映**

if (find_vma_intersection(mm, oldbrk, newbrk+page_size))

goto out;

/* ok, looks good - let it rip. */ //

執行伸長操作

if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)

goto out;

set_brk:

mm->brk = brk;

out:

retval = mm->brk;

up_write(&mm->mmap_sem);

return retval; }

brk系統呼叫分為兩種情況,一種是收縮資料區,一種是伸長操作。我們分為兩種情況來分析

二:使用者空間的收縮

從上面的**我們可以看出。使用者空間的收縮操作相應的介面是:do_munmap()。**如下:

int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)

//現在的堆尾點不可能落在空洞裡

//start

:新的邊界位址。len:收縮的長度。start+len即為舊的邊界位址。

//所以start+len肯定是屬於程序的線性位址

end = start + len;

if (mpnt->vm_start >= end)

return 0;

//如果start大於mpnt的起始位址,就會把mpnt一分為二

if (start > mpnt->vm_start)

//找到最後的乙個vma

last = find_vma(mm, end); //

把最後乙個線性區一分為二的情況

if (last && end > last->vm_start)

mpnt = prev? prev->vm_next: mm->mmap;

//將mpnt對的區間vma從程序描述符組中刪除

spin_lock(&mm->page_table_lock); //

更新頁表項,釋放頁框

unmap_region(mm, mpnt, prev, start, end);

spin_unlock(&mm->page_table_lock); //

到現在為止,所有要釋放的vma都掛在mpnt上。unmap_vma_list為對要刪除的vma鏈的處理

unmap_vma_list(mm, mpnt);

return 0; }

為了弄清楚收縮的整個過程,有必要詳細的分析一下函式所呼叫的各個子函式。

split_vma:

將乙個vma劈為成兩個:

//引數含義:

//mm:

程序的記憶體描述符vma:要劈分的vma addr:為界線位址new_below:為0時,vma為下一半 為1時,//vma為上一半

int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,

unsigned long addr, int new_below)

pol = mpol_copy(vma_policy(vma));

if (is_err(pol))

vma_set_policy(new, pol);

if (new->vm_file)

get_file(new->vm_file); //

如果定義了open操作

if (new->vm_ops && new->vm_ops->open)

new->vm_ops->open(new);

//經過前面的初始化之後,再由vma_adjust調整vma的邊界

if (new_below) else

vma_adjust(vma, vma->vm_start, addr, vma->vm_pgoff, new);

return 0; }

轉入vma_adjust():

void vma_adjust(struct vm_area_struct *vma, unsigned long start,

unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert)

它主要是將要刪除的vma鏈到一起,同時將要刪除的vma從mm中脫鏈

//引數說明:/*

mm:程序的記憶體描述符

vma:要刪除的起始vma

prev:vma

的前乙個vma區

end*/

static void

struct vm_area_struct *prev, unsigned long end)

while (vma && vma->vm_start < end); //

將要刪除的vma從鍊錶中脫落

*insertion_point = vma; //

最後無素後向指標置null

tail_vma->vm_next = null; //

由於進行了刪除操作。mmap_cache失效了,置null

mm->mmap_cache = null;/* kill the cache. */ }

接下來要分析的呼叫函式是unmap_vma_list()

它主要對刪除的vma鏈進行處理。具體**如下示:

//引數說明:

//mm:

程序的記憶體描述符

//mpnt:

要刪除的鍊錶的頭節點

static void unmap_vma_list(struct mm_struct *mm,

struct vm_area_struct *mpnt)

while (mpnt != null);

//debug

用,忽略

validate_mm(mm); }

轉向unmap_vma():

static void unmap_vma(struct mm_struct *mm, struct vm_area_struct *area)

在remove_vm_struct中:

static void remove_vm_struct(struct vm_area_struct *vma)

Linux記憶體管理 核心高階記憶體

linux核心位址對映模型 x86 cpu採用了段頁式位址對映模型。程序 中的位址為邏輯位址,經過段頁式位址對映後,才真正訪問物理記憶體。段頁式機制如下圖 linux核心位址空間劃分 通常32位linux核心位址空間劃分0 3g為使用者空間,3 4g為核心空間。注意這裡是32位核心位址空間劃分,64...

c語言學習筆記 記憶體管理 linux的記憶體映像

程式在記憶體中的儲存形式 程式儲存在flash中 程式在記憶體中主要分為以下幾段 段,資料段,唯讀資料段,bss段,堆,棧,檔案對映區,核心對映區 作業系統核心 程式一般存放在 段,在linux中又稱為文字段 資料段存放的一般是靜態變數和被初始化為非零值的全域性變數 bss段存放的是被初始化為零的全...

記憶體管理高階

dealloc是nsobject的乙個例項方法,與alloc對應,用於 開闢的記憶體空間,這個方法在物件引用計數為0是,有系統自動呼叫。通常我們在dealloc中釋放類的例項變數。dealloc的使用 void dealloc name release setter方法洩露的例項變數 super d...