linux下內(nèi)存管理學(xué)習(xí)心得(一)
然而,如果該頁(yè)被修改過(guò),操作系統(tǒng)必須保留該頁(yè)的內(nèi)容以便晚些時(shí)候在被訪問(wèn)。這種頁(yè)稱(chēng)為"臟(dirty)頁(yè)",當(dāng)它被從內(nèi)存中刪除時(shí),將被保存在一個(gè)稱(chēng)為交換文件的特殊文件中。
相對(duì)于處理器和物理內(nèi)存的速度,訪問(wèn)交換文件要很長(zhǎng)時(shí)間,操作系統(tǒng)必須在將頁(yè)寫(xiě)到磁盤(pán)以及再次使用時(shí)取回內(nèi)存的問(wèn)題上花費(fèi)心機(jī)。
如果用來(lái)決定哪一頁(yè)被淘汰或交換的算法不夠高效的話,就可能出現(xiàn)稱(chēng)為"抖動(dòng)"的情況。在這種情況下,頁(yè)面總是被寫(xiě)到磁盤(pán)又讀回來(lái),操作系統(tǒng)忙于此而不能進(jìn)行真正的工作。
linux使用"最近最少使用(Least Recently Used ,LRU)"頁(yè)面調(diào)度技巧來(lái)公平地選擇哪個(gè)頁(yè)可以從系統(tǒng)中刪除。這種設(shè)計(jì)系統(tǒng)中每個(gè)頁(yè)都有一個(gè)"年齡",年齡隨頁(yè)面被訪問(wèn)而改變。頁(yè)面被訪問(wèn)越多它越年輕;被訪問(wèn)越少越老。年老的頁(yè)是用于交換的最佳候選頁(yè)。
四、鏡像在進(jìn)程空間
我們來(lái)看看,當(dāng)我們寫(xiě)好一個(gè)應(yīng)用程序,編譯后它都有什么東東?
例如:
用命令size a.out會(huì)得到:
其中text是放的是代碼,data放的是初始化過(guò)的全局變量或靜態(tài)變量,bss放的是未初始化的全局變量或靜態(tài)變量
由于歷史原因,C程序一直由下列幾部分組成:
A.正文段。這是由cpu執(zhí)行的機(jī)器指令部分。通常,正文段是可共享的,所以即使是經(jīng)常執(zhí)行的程序(如文本編輯程序、C編譯程序、shell等)在存儲(chǔ)器中也只需要有一個(gè)副本,另外,正文段常常是只讀的,以防止程序由于意外事故而修改器自身的指令。
B.初始化數(shù)據(jù)段。通常將此段稱(chēng)為數(shù)據(jù)段,它包含了程序中需賦初值的變量。例如,C程序中任何函數(shù)之外的說(shuō)明:
int maxcount = 99;(全局變量)
C.非初始化數(shù)據(jù)段。通常將此段稱(chēng)為bss段,這一名稱(chēng)來(lái)源于早期匯編程序的一個(gè)操作,意思是"block started by symbol",在程序開(kāi)始執(zhí)行之前,內(nèi)核將此段初始化為0。函數(shù)外的說(shuō)明:
long sum[1000];
使此變量存放在非初始化數(shù)據(jù)段中。
D.棧。自動(dòng)變量以及每次函數(shù)調(diào)用時(shí)所需保存的信息都存放在此段中。每次函數(shù)調(diào)用時(shí),其返回地址、以及調(diào)用者的環(huán)境信息(例如某些機(jī)器寄存器)都存放在棧中。然后,新被調(diào)用的函數(shù)在棧上為其自動(dòng)和臨時(shí)變量分配存儲(chǔ)空間。通過(guò)以這種方式使用棧,C函數(shù)可以遞歸調(diào)用。
E.堆。通常在堆中進(jìn)行動(dòng)態(tài)存儲(chǔ)分配。由于歷史上形成的慣例,堆位于非初始化數(shù)據(jù)段頂和棧底之間。
從上圖我們看到棧空間是下增長(zhǎng)的,堆空間是從下增長(zhǎng)的,他們會(huì)會(huì)碰頭呀?一般不會(huì),因?yàn)樗麄冎g間隔很大,如:
#include
#include
int bss_var;
int data_var0 = 1;
int main()
{
printf("Test location:");
printf(" Address of main(Code Segment):%p",main);
printf("_____________________________________");
int stack_var0 = 2;
printf("Stack location:");
printf(" Initial end of stack:%p",&stack_var0);
int stack_var1 = 3;
printf(" New end of stack:%p",&stack_var1);
printf("_____________________________________");
printf("Data location:");
printf(" Address of data_var(Data Segment):%p",&data_var0);
static int data_var1 = 4;
printf(" New end of data_var(Data Segment):%p",&data_var1);
printf("_____________________________________");
printf("BSS location:");
printf(" Address of bss_var:%p",&bss_var);
printf("_____________________________________");
printf("Heap location:");
char *p = (char *)malloc(10);
printf(" Address of head_var:%p",p);
return 0;
}
運(yùn)行結(jié)果如下:
呵呵,這里我們看到地址了,這個(gè)地址是虛擬地址,這些地址時(shí)怎么來(lái)的呢?其實(shí)在我們編譯的時(shí)候,
這些地址就已經(jīng)確定了,如下圖中紅線。
也就是說(shuō),我們不論我們運(yùn)行a.out程序多少次這些地址都是一樣的。我們知道,linux操作系統(tǒng)每個(gè)進(jìn)程的地址空間都是獨(dú)立的,其實(shí)這里的獨(dú)立說(shuō)得是物理空間上得獨(dú)立。
評(píng)論