自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從開發(fā)者的角度學(xué)習(xí)Linux內(nèi)存管理

系統(tǒng) Linux
在Linux開發(fā)的過程中對于內(nèi)存的開發(fā)是有很多技巧可以掌握的。下文中就從開發(fā)者的角度去看如何進(jìn)行Linux內(nèi)核的管理。下文結(jié)合實例向大家介紹系統(tǒng)進(jìn)程與內(nèi)存之間的微妙關(guān)系。

內(nèi)存管理一向是所有操作系統(tǒng)書籍不惜筆墨重點(diǎn)討論的內(nèi)容,無論市面上或是網(wǎng)上都充斥著大量涉及內(nèi)存管理的教材和資料。因此,我們這里所要寫的Linux內(nèi)存管理采取避重就輕的策略,從理論層面就不去班門弄斧,貽笑大方了。我們最想做的和可能做到的是從開發(fā)者的角度談?wù)剬?nèi)存管理的理解,最終目的是把我們在內(nèi)核開發(fā)中使用內(nèi)存的經(jīng)驗和對Linux內(nèi)存管理的認(rèn)識與大家共享。

關(guān)于Linux內(nèi)核的具體知識大家可以參考51CTO精選譯文:Linux內(nèi)核入門,包教會

進(jìn)程如何使用內(nèi)存?

毫無疑問,所有進(jìn)程(執(zhí)行的程序)都必須占用一定數(shù)量的內(nèi)存,它或是用來存放從磁盤載入的程序代碼,或是存放取自用戶輸入的數(shù)據(jù)等等。不過進(jìn)程對這些內(nèi)存的管理方式因內(nèi)存用途不一而不盡相同,有些內(nèi)存是事先靜態(tài)分配和統(tǒng)一回收的,而有些卻是按需要動態(tài)分配和回收的。

對任何一個普通進(jìn)程來講,它都會涉及到5種不同的數(shù)據(jù)段。稍有編程知識的朋友都能想到這幾個數(shù)據(jù)段中包含有“程序代碼段”、“程序數(shù)據(jù)段”、“程序堆棧段”等。不錯,這幾種數(shù)據(jù)段都在其中,但除了以上幾種數(shù)據(jù)段之外,進(jìn)程還另外包含兩種數(shù)據(jù)段。下面我們來簡單歸納一下進(jìn)程對應(yīng)的內(nèi)存空間中所包含的5種不同的數(shù)據(jù)區(qū)。

代碼段:代碼段是用來存放可執(zhí)行文件的操作指令,也就是說是它是可執(zhí)行程序在內(nèi)存中的鏡像。代碼段需要防止在運(yùn)行時被非法修改,所以只準(zhǔn)許讀取操作,而不允許寫入(修改)操作——它是不可寫的。

數(shù)據(jù)段:數(shù)據(jù)段用來存放可執(zhí)行文件中已初始化全局變量,換句話說就是存放程序靜態(tài)分配的變量和全局變量。

BSS段:BSS段包含了程序中未初始化的全局變量,在內(nèi)存中 bss段全部置零。

堆(heap):堆是用于存放進(jìn)程運(yùn)行中被動態(tài)分配的內(nèi)存段,它的大小并不固定,可動態(tài)擴(kuò)張或縮減。當(dāng)進(jìn)程調(diào)用malloc等函數(shù)分配內(nèi)存時,新分配的內(nèi)存就被動態(tài)添加到堆上(堆被擴(kuò)張);當(dāng)利用free等函數(shù)釋放內(nèi)存時,被釋放的內(nèi)存從堆中被剔除(堆被縮減)

棧:棧是用戶存放程序臨時創(chuàng)建的局部變量,也就是說我們函數(shù)括弧“{}”中定義的變量(但不包括static聲明的變量,static意味著在數(shù)據(jù)段中存放變量)。除此以外,在函數(shù)被調(diào)用時,其參數(shù)也會被壓入發(fā)起調(diào)用的進(jìn)程棧中,并且待到調(diào)用結(jié)束后,函數(shù)的返回值也會被存放回棧中。由于棧的先進(jìn)先出特點(diǎn),所以棧特別方便用來保存/恢復(fù)調(diào)用現(xiàn)場。從這個意義上講,我們可以把堆??闯梢粋€寄存、交換臨時數(shù)據(jù)的內(nèi)存區(qū)。

進(jìn)程如何組織這些區(qū)域?

上述幾種內(nèi)存區(qū)域中數(shù)據(jù)段、BSS和堆通常是被連續(xù)存儲的——內(nèi)存位置上是連續(xù)的,而代碼段和棧往往會被獨(dú)立存放。有趣的是,堆和棧兩個區(qū)域關(guān)系很“曖昧”,他們一個向下“長”(i386體系結(jié)構(gòu)中棧向下、堆向上),一個向上“長”,相對而生。但你不必?fù)?dān)心他們會碰頭,因為他們之間間隔很大(到底大到多少,你可以從下面的例子程序計算一下),絕少有機(jī)會能碰到一起。

下圖簡要描述了進(jìn)程內(nèi)存區(qū)域的分布:

#p#

“事實勝于雄辯”,我們用一個小例子(原形取自《User-Level Memory Management》)來展示上面所講的各種內(nèi)存區(qū)的差別與位置。

#include
#include
#include
int bss_var;
int data_var0=1;
int main(int argc,char **argv)
{
printf("below are addresses of types of process's mem\n");
printf("Text location:\n");
printf("\tAddress of main(Code Segment):%p\n",main);
printf("____________________________\n");
int stack_var0=2;
printf("Stack Location:\n");
printf("\tInitial end of stack:%p\n",&stack_var0);
int stack_var1=3;
printf("\tnew end of stack:%p\n",&stack_var1);
printf("____________________________\n");
printf("Data Location:\n");
printf("\tAddress of data_var(Data Segment):%p\n",&data_var0);
static int data_var1=4;
printf("\tNew end of data_var(Data Segment):%p\n",&data_var1);
printf("____________________________\n");
printf("BSS Location:\n");
printf("\tAddress of bss_var:%p\n",&bss_var);
printf("____________________________\n");
char *b = sbrk((ptrdiff_t)0);
printf("Heap Location:\n");
printf("\tInitial end of heap:%p\n",b);
brk(b+4);
b=sbrk((ptrdiff_t)0);
printf("\tNew end of heap:%p\n",b);
return 0;
}

 

它的結(jié)果如下

below are addresses of types of process's mem
Text location:
Address of main(Code Segment):0x8048388
____________________________
Stack Location:
Initial end of stack:0xbffffab4
new end of stack:0xbffffab0
____________________________
Data Location:
Address of data_var(Data Segment):0x8049758
New end of data_var(Data Segment):0x804975c
__________________________
BSS Location:
Address of bss_var:0x8049864
____________________________
Heap Location:
Initial end of heap:0x8049868
New end of heap:0x804986c

 

利用size命令也可以看到程序的各段大小,比如執(zhí)行size example會得到

text data bss dec hex filename
1654 280 8 1942 796 example

但這些數(shù)據(jù)是程序編譯的靜態(tài)統(tǒng)計,而上面顯示的是進(jìn)程運(yùn)行時的動態(tài)值,但兩者是對應(yīng)的。

通過前面的例子,我們對進(jìn)程使用的邏輯內(nèi)存分布已先睹為快。這部分我們就繼續(xù)進(jìn)入操作系統(tǒng)內(nèi)核看看,進(jìn)程對內(nèi)存具體是如何進(jìn)行分配和管理的。

從用戶向內(nèi)核看,所使用的內(nèi)存表象形式會依次經(jīng)歷“邏輯地址”——“線性地址”——“物理地址”幾種形式(關(guān)于幾種地址的解釋在前面已經(jīng)講述了)。邏輯地址經(jīng)段機(jī)制轉(zhuǎn)化成線性地址;線性地址又經(jīng)過頁機(jī)制轉(zhuǎn)化為物理地址。(但是我們要知道Linux系統(tǒng)雖然保留了段機(jī)制,但是將所有程序的段地址都定死為0-4G,所以雖然邏輯地址和線性地址是兩種不同的地址空間,但在Linux中邏輯地址就等于線性地址,它們的值是一樣的)。沿著這條線索,我們所研究的主要問題也就集中在下面幾個問題。

1.進(jìn)程空間地址如何管理?

2.進(jìn)程地址如何映射到物理內(nèi)存?

3.物理內(nèi)存如何被管理?

以及由上述問題引發(fā)的一些子問題。如系統(tǒng)虛擬地址分布;內(nèi)存分配接口;連續(xù)內(nèi)存分配與非連續(xù)內(nèi)存分配等。#p#

進(jìn)程內(nèi)存空間

Linux操作系統(tǒng)采用虛擬內(nèi)存管理技術(shù),使得每個進(jìn)程都有各自互不干涉的進(jìn)程地址空間。該空間是塊大小為4G的線性虛擬空間,用戶所看到和接觸到的都是該虛擬地址,無法看到實際的物理內(nèi)存地址。利用這種虛擬地址不但能起到保護(hù)操作系統(tǒng)的效果(用戶不能直接訪問物理內(nèi)存),而且更重要的是,用戶程序可使用比實際物理內(nèi)存更大的地址空間(具體的原因請看硬件基礎(chǔ)部分)。

在討論進(jìn)程空間細(xì)節(jié)前,這里先要澄清下面幾個問題:

***、4G的進(jìn)程地址空間被人為的分為兩個部分——用戶空間與內(nèi)核空間。用戶空間從0到3G(0xC0000000),內(nèi)核空間占據(jù)3G到4G。用戶進(jìn)程通常情況下只能訪問用戶空間的虛擬地址,不能訪問內(nèi)核空間虛擬地址。只有用戶進(jìn)程進(jìn)行系統(tǒng)調(diào)用(代表用戶進(jìn)程在內(nèi)核態(tài)執(zhí)行)等時刻可以訪問到內(nèi)核空間。

第二、用戶空間對應(yīng)進(jìn)程,所以每當(dāng)進(jìn)程切換,用戶空間就會跟著變化;而內(nèi)核空間是由內(nèi)核負(fù)責(zé)映射,它并不會跟著進(jìn)程改變,是固定的。內(nèi)核空間地址有自己對應(yīng)的頁表(init_mm.pgd),用戶進(jìn)程各自有不同的頁表。

第三、每個進(jìn)程的用戶空間都是完全獨(dú)立、互不相干的。不信的話,你可以把上面的程序同時運(yùn)行10次(當(dāng)然為了同時運(yùn)行,讓它們在返回前一同睡眠100秒吧),你會看到10個進(jìn)程占用的線性地址一模一樣。

進(jìn)程內(nèi)存管理

進(jìn)程內(nèi)存管理的對象是進(jìn)程線性地址空間上的內(nèi)存鏡像,這些內(nèi)存鏡像其實就是進(jìn)程使用的虛擬內(nèi)存區(qū)域(memory region)。進(jìn)程虛擬空間是個32或64位的“平坦”(獨(dú)立的連續(xù)區(qū)間)地址空間(空間的具體大小取決于體系結(jié)構(gòu))。要統(tǒng)一管理這么大的平坦空間可絕非易事,為了方便管理,虛擬空間被劃分為許多大小可變的(但必須是4096的倍數(shù))內(nèi)存區(qū)域,這些區(qū)域在進(jìn)程線性地址中像停車位一樣有序排列。這些區(qū)域的劃分原則是“將訪問屬性一致的地址空間存放在一起”,所謂訪問屬性在這里無非指的是“可讀、可寫、可執(zhí)行等”。

如果你要查看某個進(jìn)程占用的內(nèi)存區(qū)域,可以使用命令cat /proc//maps獲得(pid是進(jìn)程號,你可以運(yùn)行上面我們給出的例子——./example &;pid便會打印到屏幕),你可以發(fā)現(xiàn)很多類似于下面的數(shù)字信息。

由于程序example使用了動態(tài)庫,所以除了example本身使用的的內(nèi)存區(qū)域外,還會包含那些動態(tài)庫使用的內(nèi)存區(qū)域(區(qū)域順序是:代碼段、數(shù)據(jù)段、bss段)。

我們下面只抽出和example有關(guān)的信息,除了前兩行代表的代碼段和數(shù)據(jù)段外,***一行是進(jìn)程使用的棧空間。

08048000-08049000 r-xp 00000000 03:03 439029 /home/mm/src/example 
08049000-0804a000 rw-p 00000000 03:03 439029 /home/mm/src/example
bfffe000 - c0000000 rwxp ffff000 00:00 0

每行數(shù)據(jù)格式如下:

(內(nèi)存區(qū)域)開始-結(jié)束 訪問權(quán)限 偏移 主設(shè)備號:次設(shè)備號 i節(jié)點(diǎn) 文件。

注意,你一定會發(fā)現(xiàn)進(jìn)程空間只包含三個內(nèi)存區(qū)域,似乎沒有上面所提到的堆、bss等,其實并非如此,程序內(nèi)存段和進(jìn)程地址空間中的內(nèi)存區(qū)域是種模糊對應(yīng),也就是說,堆、bss、數(shù)據(jù)段(初始化過的)都在進(jìn)程空間中由數(shù)據(jù)段內(nèi)存區(qū)域表示。

在Linux內(nèi)核中對應(yīng)進(jìn)程內(nèi)存區(qū)域的數(shù)據(jù)結(jié)構(gòu)是: vm_area_struct, 內(nèi)核將每個內(nèi)存區(qū)域作為一個單獨(dú)的內(nèi)存對象管理,相應(yīng)的操作也都一致。采用面向?qū)ο蠓椒ㄊ筕MA結(jié)構(gòu)體可以代表多種類型的內(nèi)存區(qū)域--比如內(nèi)存映射文件或進(jìn)程的用戶空間棧等,對這些區(qū)域的操作也都不盡相同。

vm_area_strcut結(jié)構(gòu)比較復(fù)雜,關(guān)于它的詳細(xì)結(jié)構(gòu)請參閱相關(guān)資料。我們這里只對它的組織方法做一點(diǎn)補(bǔ)充說明。vm_area_struct是描述進(jìn)程地址空間的基本管理單元,對于一個進(jìn)程來說往往需要多個內(nèi)存區(qū)域來描述它的虛擬空間,如何關(guān)聯(lián)這些不同的內(nèi)存區(qū)域呢?大家可能都會想到使用鏈表,的確vm_area_struct結(jié)構(gòu)確實是以鏈表形式鏈接,不過為了方便查找,內(nèi)核又以紅黑樹(以前的內(nèi)核使用平衡樹)的形式組織內(nèi)存區(qū)域,以便降低搜索耗時。并存的兩種組織形式,并非冗余:鏈表用于需要遍歷全部節(jié)點(diǎn)的時候用,而紅黑樹適用于在地址空間中定位特定內(nèi)存區(qū)域的時候。內(nèi)核為了內(nèi)存區(qū)域上的各種不同操作都能獲得高性能,所以同時使用了這兩種數(shù)據(jù)結(jié)構(gòu)。

下圖反映了進(jìn)程地址空間的管理模型:

進(jìn)程的地址空間對應(yīng)的描述結(jié)構(gòu)是“內(nèi)存描述符結(jié)構(gòu)”,它表示進(jìn)程的全部地址空間,——包含了和進(jìn)程地址空間有關(guān)的全部信息,其中當(dāng)然包含進(jìn)程的內(nèi)存區(qū)域。
 

【編輯推薦】

  1. Linux內(nèi)核入門,包教會
  2. Linux內(nèi)核編譯中的九個技巧
  3. Linux內(nèi)存監(jiān)控過程詳解
  4. 簡單介紹Linux內(nèi)存手動釋放方法
  5. Linux內(nèi)存使用情況查看單位顯示
責(zé)任編輯:張浩 來源: 藍(lán)色精靈的博客
相關(guān)推薦

2012-09-27 09:03:02

開發(fā)者iOS 6iPhone 5

2023-02-03 09:52:10

開發(fā)者框架GoFrame

2014-04-14 11:23:27

WP8.1Build2014

2024-02-04 09:18:00

Python內(nèi)存管理垃圾回收

2013-03-11 11:20:05

2023-09-11 08:47:20

Go模式uilder

2009-06-02 15:58:34

LinuxChrome開發(fā)

2012-06-13 01:23:30

開發(fā)者程序員

2009-06-01 09:59:57

LinuxChrome開發(fā)

2012-04-11 09:26:13

內(nèi)核Linux 開發(fā)

2021-09-04 19:54:40

開發(fā)者技術(shù)管理

2016-09-08 16:48:35

華為開發(fā)者社區(qū)HDG

2023-11-26 00:17:21

2018-11-23 11:50:02

Linux開發(fā)者編程書籍

2018-11-23 09:07:00

Linux開發(fā)者書籍

2009-12-09 11:08:00

Linux開發(fā)者

2019-08-08 14:40:18

開發(fā)者技能工具

2010-06-21 16:39:14

2012-10-31 16:12:11

2019-07-04 09:00:00

Web控制器架構(gòu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號