Linux內存分布


環境:Linux,redhat

當一段程序被編譯成為一個可執行的文件時,這個時候它已經被划分成代碼段、數據段、棧段、.bss段、堆等部分。

各段的作用是:

1.代碼段(.text):代碼,全局常量(const),只讀變量和字符串常量(有可能在代碼段,一般被放在只讀數據".rodata"段,還有可能就在“.data”段)
2.數據段(.data):全局變量(初始化以及未初始化的)、靜態變量(全局的和局部的、初始化的以及未初始化的)。數據段包括初始化的數據和未初始化的數據(BSS)兩部分。BSS段存放的是未初始化的全局變量和靜態變量。BSS段在不占可執行文件空間,文件只記錄BSS段的在內存中的開始和結束地址。
3.堆:動態分配的區域。
4.棧:局部變量(初始化以及未初始化的,但不包含靜態變量)、局部只讀變量(const)。

SNAGHTMLeae3fc

為什么需要分段呢,這是有理由的,總的來說,第一點是為了將程序的層次划分清晰,不過這點似乎不是最重要的原因才說得過去;第二點,① 由編譯器負責挑選出數據具備的屬性,從而根據屬性將程序片段分類,比如,划分出了只讀屬性的代碼段和可寫屬性的數據段;② 由內核分配段的屬性(例如讀、寫、執行等); ③ 這時候就可以將段描述符寫進CPU的段寄存器中了,這就相當於操作系統定義段,然后要告知CPU,操作系統對段做了些什么,好讓CPU做出相應的准備(例如只讀段,CPU就不能去寫,寫操作就會產生異常)。

具體的講解在我轉載的這篇文章中已經說的很是詳細了。http://my.oschina.net/yuyounglife/blog/706376

這里我拿幾段重要的話出來。

做過開發的同學都清楚,盡量把同一屬性的數據放在一起,這樣易於維護。這一點類似於MVC,在程序邏輯中把模型、視圖、控制這三部分分開,這樣更新各部分時,不會影響到其他模塊。

將數據和代碼分開的好處有三點。

第一,可以為它們賦予不同的屬性。

例如數據本身是需要修改的,所以數據就需要有可寫的屬性,不讓數據段可寫,那程序根本就無法執行啦。程序中的代碼是不能被更改的,這樣就要求代碼段具備只讀的屬性。真要是在運行過程中程序的下一條指令被修改了,誰知道會產生什么樣的災難。

第二,為了提高CPU內部緩存的命中率。

大伙兒知道,緩存起作用的原因是程序的局部性原理。在CPU內部也有緩存機制,將程序中的指令和數據分離,這有利於增強程序的局部性。CPU內部有針對數據和針對指令的兩種緩存機制,因此,將數據和代碼分開存儲將使程序運行得更快。

第三,節省內存。

程序中存在一些只讀的部分,比如代碼,當一個程序的多個副本同時運行時(比如同時執行多個ls命令時),沒必要在內存中同時存在多個相同的代碼段,這將浪費有限的物理內存資源,只要把這一個代碼段共享就可以了。

/* 國嵌代碼addr.c */
 
#include<stdio.h>
#include<stdlib.h>
int global_init_a = 0; // 全局 初始化的變量 數據段
int global_uninit_a;   // 全局 未初始化 BSS段
static int static_global_init_a = 1; // 全局 靜態 初始化 數據段
static int static_global_uninit_a;   // 全局 靜態 未初始化 BSS段
const int const_global_a=1;          // 全局 常量 代碼段
 
int global_init_b = 0; // 全局 初始化 數據段
int global_uninit_b;   // 全局 未初始化 BSS段
static int static_global_init_b = 1; // 全局 靜態 初始化 數據段
static int static_global_uninit_b;   // 全局 靜態 未初始化 BSS段
const int const_global_b=1;          // 全局 常量 代碼段
 
int main()
{
int local_init_a = 1;  // 局部 初始化 棧
int local_uninit_a;    // 局部 未初始化 棧 
static int static_local_init_a = 1; // 局部 靜態 初始化 數據段
static int static_local_uninit_a;   // 局部 靜態 未初始化 BSS段
const int const_local_a = 1;   // 局部 常量 棧
 
 int local_init_b = 1; // 局部 初始化 棧
int local_uninit_b;   // 局部 未初始化 棧
static int static_local_init_b = 1; // 局部 靜態 初始化 數據段
static int static_local_uninit_b;   // 局部 靜態 未初始化 BSS段
const int const_local_b = 1; // 局部 常量 棧
 int * malloc_p_a;  // malloc分配得到的局部 堆
malloc_p_a = malloc(sizeof(int));
 
printf("&global_init_a=%p, global_init_a=%d\n", &global_init_a, global_init_a);
printf("&global_uninit_a=%p, global_uninit_a=%d\n", &global_uninit_a, global_uninit_a);
printf("&static_global_init_a=%p, static_global_init_a=%d\n", &static_global_init_a, static_global_init_a);
printf("&static_global_uninit_a=%p, static_global_uninit_a=%d\n", &static_global_uninit_a, static_global_uninit_a);
printf("&const_global_a=%p, const_global_a=%d\n", &const_global_a, const_global_a);
 
printf("&global_init_b=%p, global_init_b=%d\n", &global_init_b, global_init_b);
printf("&global_uninit_b=%p, global_uninit_b=%d\n", &global_uninit_b, global_uninit_b);
printf("&static_global_init_b=%p, static_global_init_b=%d\n", &static_global_init_b, static_global_init_b);
printf("&static_global_uninit_b=%p, static_global_uninit_b=%d\n", &static_global_uninit_b, static_global_uninit_b);
printf("&const_global_b=%p, const_global_b=%d\n", &const_global_b, const_global_b);
 printf("&local_init_a=%p, local_init_a=%d\n", &local_init_a, local_init_a);
printf("&local_uninit_a=%p, local_uninit_a=%d\n", &local_uninit_a, local_uninit_a);
printf("&static_local_init_a=%p, static_local_init_a=%d\n", &static_local_init_a, static_local_init_a);
printf("&static_local_uninit_a=%p, static_local_uninit_a=%d\n", &static_local_uninit_a, static_local_uninit_a);
printf("&const_local_a=%p, const_local_a=%d\n", &const_local_a, const_local_a);
 
printf("&local_init_b=%p, local_init_b=%d\n", &local_init_b, local_init_b);
printf("&local_uninit_b=%p, local_uninit_b=%d\n", &local_uninit_b, local_uninit_b);
printf("&static_local_init_b=%p, static_local_init_b=%d\n", &static_local_init_b, static_local_init_b);
printf("&static_local_uninit_b=%p, static_local_uninit_b=%d\n", &static_local_uninit_b, static_local_uninit_b);
printf("&const_local_b=%p, const_local_b=%d\n", &const_local_b, const_local_b);
 printf("&malloc_p_a=%p, *malloc_p_a=%d\n", malloc_p_a, *malloc_p_a);
printf("&global_init_a=%p, global_init_a=%d\n", &global_init_a, global_init_a);
 
while(1)
;
 return 0;
}
編譯程序,gcc addr.c –o addr     然后運行程序   ./addr

ps aux 查看進程的進程號

cat /proc/6882(進程號)/maps   查看各段地址, 查看更為詳細的地址readelf –S addr

對照着段的信息和程序打印出來的地址即可查到各個變量所在段。

這篇文章講得也不錯。http://www.jianshu.com/p/9f981f6433d1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM