LINUX系统编程 LINUX 虚拟内存
生活随笔
收集整理的這篇文章主要介紹了
LINUX系统编程 LINUX 虚拟内存
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
LINUX 虛擬內存
以32位操作系統為例子,因為64位系統虛擬地址過大為2^64,32位僅僅為2^32=4G更利于描述,但是原理東西都一樣
這首先要從程序和進程之間的關系開始,我們一般寫好一段C\C++代碼編譯后僅僅為可執行文件假設為a.out,我們
運行a.out的時候,這個才叫進程,進程是OS級別抽象的實體(PCB task_struct結構體),為程序運行進行各種檢查和
系統資源分配,一個PCB包含部分信息如下:
(摘至刑文鵬LINUX系統編程講義)
* 進程id。系統中每個進程有唯一的id,在C語言中用pid_t類型表示,其實就是一個非
負整數。
* 進程的狀態,有運行、掛起、停止、僵尸等狀態。
* 進程切換時需要保存和恢復的一些CPU寄存器。
* 描述虛擬地址空間的信息。
* 描述控制終端的信息。
* 當前工作目錄(Current Working Directory)。
* umask掩碼。
* 文件描述符表,包含很多指向file結構體的指針。
* 和信號相關的信息。
* 用戶id和組id。
* 控制終端、Session和進程組。
* 進程可以使用的資源上限(Resource Limit)
每個進程分配的內存包含很多稱之為段的部分組成并且放到0-3G用戶態虛擬地址空間中,3-4G為kernel太虛擬地址(注意我們以32位為列),
PCB就存放在我們的kernel態中。
下面描述0-3G用戶態虛擬內存段
由下向上分別是
1、代碼段,是程序運行的機器代碼,一個程序代碼可以多個程序
? ?同時運行,那么這個代碼段可以同時存在于不同進程的不同
? ?虛擬內存地址中,等會用圖說明
2、初始化數據段,這個就是C\C++已經初始化的全局變量和靜態變量
? ?我們知道靜態變量是存在于程序結束,而全局變量(非靜態)的作用
? ?域也是全部代碼塊,那么這些變量需要放到一個非棧空間中
? ?(關于靜態變量可以查看如下鏈接
??http://blog.itpub.net/7728585/viewspace-2119670/
? ?)
3、未初始化數據段,為初始化的全局變量和靜態變量,未初始化本
? ?段的內容初始化為0
4、堆(heap)段,是在運行的時候動態進程分配的內存區域,比如malloc
下面以一段簡單代碼說明,目的僅僅在于說明上面說的:
(未分配虛擬內存地址)
5、棧(stack)段,我們知道棧是一個后進先出的數據結構,用于存儲局部
? ?變量,實參和返回值。它由棧幀組成(stack frames),每次新的函數調用
? ?都會分配一個新的棧幀比如下面的getv rev都在main函數棧幀里面。
? ? 而沒有使用到局部變量t 則在add函數棧幀里面
6、argc,environ 數組信息,固定大小
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef unsigned int uint;
static uint step=1024;//全局初始化靜態變量,初始化數據段
uint iniv=1; //全局初始化非靜態變量,可以使用extern訪問,初始化數據段
static uint zero;//全局未初始化靜態變量,未初始化數據段
uint add(uint inv) //值傳遞 棧 for add funcation?stack frame
{
? ? ?int t; //?棧?for?add funcation?stack frames ? ? ?return inv*step+zero; //棧 for add funcation?stack frames
}
int main(void)
{
????????uint getv = 10; //棧 for main funcation?stack frame
????????uint rev; //棧 for main funcation?stack frames
????????char* p; //棧 for main funcation?stack frames
????????rev = add(getv);
????????p = calloc(6,1); //堆
????????strcpy(p,"test:");
????????printf("%s%u\n",p,rev);
????????return 0;
} 本來很多圖像自己畫,但是發現比較麻煩,并且效果可能并不如原圖好,所以直接
摘錄.
關于進程各段組織如下(摘自UNIX/LINUX系統編程手冊)
關于進程用戶態和內核態的關系如下(摘自刑文鵬LINUX系統編程講義)
為了方便管理LINUX將內存分為叫做頁幀的單元(我們熟悉的4K),然后內核中就需要保存一份進程虛擬地址到實際地址的映射表,如果訪問的數據不再物理內存
中就發生page fault,將磁盤中的數據復制到物理內存,建立虛擬地址到物理內存的映射關系,一個進程訪問數據是通過虛擬地址進行訪問,然后通過映射表對應
到實際的物理內存。
由于64位系統需要管理的內存頁非常巨大在LINUX中使用三級或者四級(內核2.6.11以上使用四級)映射表,關于映射表實際實現這里沒有過多討論,因為這個屬于
LINUX內核原理的東西,我也沒有能力研究。
(實際是虛擬地址--》線性地址--》物理地址,但是LINUX中虛擬地址和線性地址是相同的。)
映射表直觀圖(摘自UNIX/LINUX系統編程手冊)
四級映射表(摘自pdf內存尋址)
最后我們需要牢牢的記住的就是每個進程都有0-4G的虛擬地址空間可供分配,當然沒有分配就是未使用的,進程訪問的是內存虛擬地址,虛擬地址空間的數據可能并不
在實際內存中,當進程訪問到虛擬地址的數據并不在內存中,那么發生page fault,將磁盤中的數據復制到物理內存,建立虛擬地址到物理內存的映射關系,如果在實際內存不足的情況下啟用swap做為物理內存的補充,將部分曾經使用過的數據而當前沒有使用的數據拷貝到SWAP中。而數據的過期處理一般為用戶程序自己控制比如LRU鏈表。
(這也是為什么某些數據庫比如ORACLE MYSQL,在一臺64G的內存的機器上同時跑2個實例都分配64G左右內存能夠起來,但是過一段時間可能報內存不足的原因)
某些觀點為作者自己觀點如果有誤請指出
參考資料:
1、UNIX/LINUX系統編程手冊
2、LINUX操作系統原理與應用
3、刑文鵬LINUX系統編程講義
4、pdf內存尋址
以32位操作系統為例子,因為64位系統虛擬地址過大為2^64,32位僅僅為2^32=4G更利于描述,但是原理東西都一樣
這首先要從程序和進程之間的關系開始,我們一般寫好一段C\C++代碼編譯后僅僅為可執行文件假設為a.out,我們
運行a.out的時候,這個才叫進程,進程是OS級別抽象的實體(PCB task_struct結構體),為程序運行進行各種檢查和
系統資源分配,一個PCB包含部分信息如下:
(摘至刑文鵬LINUX系統編程講義)
* 進程id。系統中每個進程有唯一的id,在C語言中用pid_t類型表示,其實就是一個非
負整數。
* 進程的狀態,有運行、掛起、停止、僵尸等狀態。
* 進程切換時需要保存和恢復的一些CPU寄存器。
* 描述虛擬地址空間的信息。
* 描述控制終端的信息。
* 當前工作目錄(Current Working Directory)。
* umask掩碼。
* 文件描述符表,包含很多指向file結構體的指針。
* 和信號相關的信息。
* 用戶id和組id。
* 控制終端、Session和進程組。
* 進程可以使用的資源上限(Resource Limit)
每個進程分配的內存包含很多稱之為段的部分組成并且放到0-3G用戶態虛擬地址空間中,3-4G為kernel太虛擬地址(注意我們以32位為列),
PCB就存放在我們的kernel態中。
下面描述0-3G用戶態虛擬內存段
由下向上分別是
1、代碼段,是程序運行的機器代碼,一個程序代碼可以多個程序
? ?同時運行,那么這個代碼段可以同時存在于不同進程的不同
? ?虛擬內存地址中,等會用圖說明
2、初始化數據段,這個就是C\C++已經初始化的全局變量和靜態變量
? ?我們知道靜態變量是存在于程序結束,而全局變量(非靜態)的作用
? ?域也是全部代碼塊,那么這些變量需要放到一個非棧空間中
? ?(關于靜態變量可以查看如下鏈接
??http://blog.itpub.net/7728585/viewspace-2119670/
? ?)
3、未初始化數據段,為初始化的全局變量和靜態變量,未初始化本
? ?段的內容初始化為0
4、堆(heap)段,是在運行的時候動態進程分配的內存區域,比如malloc
下面以一段簡單代碼說明,目的僅僅在于說明上面說的:
(未分配虛擬內存地址)
5、棧(stack)段,我們知道棧是一個后進先出的數據結構,用于存儲局部
? ?變量,實參和返回值。它由棧幀組成(stack frames),每次新的函數調用
? ?都會分配一個新的棧幀比如下面的getv rev都在main函數棧幀里面。
? ? 而沒有使用到局部變量t 則在add函數棧幀里面
6、argc,environ 數組信息,固定大小
點擊(此處)折疊或打開
摘錄.
關于進程各段組織如下(摘自UNIX/LINUX系統編程手冊)
關于進程用戶態和內核態的關系如下(摘自刑文鵬LINUX系統編程講義)
為了方便管理LINUX將內存分為叫做頁幀的單元(我們熟悉的4K),然后內核中就需要保存一份進程虛擬地址到實際地址的映射表,如果訪問的數據不再物理內存
中就發生page fault,將磁盤中的數據復制到物理內存,建立虛擬地址到物理內存的映射關系,一個進程訪問數據是通過虛擬地址進行訪問,然后通過映射表對應
到實際的物理內存。
由于64位系統需要管理的內存頁非常巨大在LINUX中使用三級或者四級(內核2.6.11以上使用四級)映射表,關于映射表實際實現這里沒有過多討論,因為這個屬于
LINUX內核原理的東西,我也沒有能力研究。
(實際是虛擬地址--》線性地址--》物理地址,但是LINUX中虛擬地址和線性地址是相同的。)
映射表直觀圖(摘自UNIX/LINUX系統編程手冊)
四級映射表(摘自pdf內存尋址)
最后我們需要牢牢的記住的就是每個進程都有0-4G的虛擬地址空間可供分配,當然沒有分配就是未使用的,進程訪問的是內存虛擬地址,虛擬地址空間的數據可能并不
在實際內存中,當進程訪問到虛擬地址的數據并不在內存中,那么發生page fault,將磁盤中的數據復制到物理內存,建立虛擬地址到物理內存的映射關系,如果在實際內存不足的情況下啟用swap做為物理內存的補充,將部分曾經使用過的數據而當前沒有使用的數據拷貝到SWAP中。而數據的過期處理一般為用戶程序自己控制比如LRU鏈表。
(這也是為什么某些數據庫比如ORACLE MYSQL,在一臺64G的內存的機器上同時跑2個實例都分配64G左右內存能夠起來,但是過一段時間可能報內存不足的原因)
某些觀點為作者自己觀點如果有誤請指出
參考資料:
1、UNIX/LINUX系統編程手冊
2、LINUX操作系統原理與應用
3、刑文鵬LINUX系統編程講義
4、pdf內存尋址
來自 “ ITPUB博客 ” ,鏈接:http://blog.itpub.net/7728585/viewspace-2129073/,如需轉載,請注明出處,否則將追究法律責任。
轉載于:http://blog.itpub.net/7728585/viewspace-2129073/
總結
以上是生活随笔為你收集整理的LINUX系统编程 LINUX 虚拟内存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文档服务器地址如何进入,如何登陆服务器地
- 下一篇: Note For Linux By Je