天天看點

未初始化全局變量未初始化全局變量

未初始化全局變量

  為下一篇介紹程序記憶體分布做準備,這一篇先來介紹一下未初始化全局變量:

  未初始化全局變量,這名字就很直白,就是 C 程式中定義成全局作用域而又沒有初始化的變量,我們知道這種變量在程式運作後是被自動初始化為 全0 的。編譯器編譯的時候會将這類變量收集起來集中放置到 .bss 段中,這個段隻記錄了段長,沒有實際上的内容(全是0,沒必要存儲),在程式被裝載時作業系統會為它配置設定等于段長的記憶體,并全部初始化為0。

  這有兩個 C程式,都定義了全局數組 data(長度為1M,占用記憶體4MB),一個部分初始化(bss_init1.c),一個未初始化(bss_uninit1.c):

bss_init1.c:

#include <stdio.h>
#include <windows.h>

#define MAXLEN 1024*1024

int data[MAXLEN]={1,};

int main()
{
    Sleep(-1);
    return 0;
}
           

bss_uninit1.c:

#include <stdio.h>
#include <windows.h>

#define MAXLEN 1024*1024

int data[MAXLEN];

int main()
{
    Sleep(-1);
    return 0;
}
           

  

編譯以上兩個程式後:

未初始化全局變量未初始化全局變量

  可以看到有初始化的可執行檔案的大小差不多是4MB,而未初始化的隻有47KB!這就是 .bss 段有段長,而沒有實際内容的表現。用 UltraEdit 打開 bss_init1.exe 可看到檔案中大部分是全0(data數組的内容):

未初始化全局變量未初始化全局變量

  但是接下來運作(return 0 之前的 Sleep(-1) 保證了程式暫時不會退出)的時候,卻發現 bss_init1.exe 占用的空間明顯少于 4MB,這是怎麼回事呢?

未初始化全局變量未初始化全局變量

  這就涉及程式裝載的政策了。早期的作業系統(如:linux 0.01)采用的是一次裝載:将可執行檔案一次性完整裝入記憶體後再執行程式。不管程式是 1KB 還是 60MB,都要等全部裝入記憶體後才能執行,這顯然是不太合理的。

  而現在的作業系統都是采用延遲裝載: 将程序空間映射到可執行檔案之後就開始執行了,執行的時候如果發現要讀/寫的頁不在記憶體中,就根據映射關系去讀取進來,然後繼續執行應用程式(應該是在頁保護異常的進行中實作的)。

  bss_init1.exe 肯定是被映射了,而程式中又沒有對 data 數組進行讀/寫操作,是以作業系統也就懶得去裝入這片記憶體了。下面修改一下這兩個程式:在 Sleep(-1) 前将 data 數組的每個元素指派為 -1:

int i;
for(i=0; i<MAXLEN; ++i)
    data[i] = -1;
           

  

再運作,它們占用的記憶體都是 4M 了:

未初始化全局變量未初始化全局變量

繼續閱讀