在前面的章節中,我們已經了解到可執行檔案是如何對映到計算機記憶體裡的,本節將再深化一下對這方面的理解,順便結合上一章中關於動態鏈結的內容,看看加上動態鏈結之後程序的位址空間是如何分布的。
現代的應用程式都執行在乙個記憶體空間裡,在32位的系統裡,這個記憶體空間擁有4gb(2的32次方)的定址能力。相對於16位時代i386的段位址加段內偏移的定址模式,如今的應用程式可以直接使用32位的位址進行定址,這被稱為平坦(flat)的記憶體模型。在平坦的記憶體模型中,整個記憶體是乙個統一的位址空間,使用者可以使用乙個32位的指標訪問任意記憶體位置。例如:
int p = (int)0x12345678;
++*p;
這段**展示了如何直接讀寫指定位址的記憶體資料。不過,儘管當今的記憶體空間號稱是平坦的,但實際上記憶體仍然在不同的位址區間上有著不同的地位,例如,大多數作業系統都會將4gb的記憶體空間中的一部分挪給核心使用,應用程式無法直接訪問這一段記憶體,這一部分記憶體位址被稱為核心空間。windows在預設情況下會將高位址的2gb空間分配給核心(也可配置為1gb),而linux預設情況下將高位址的1gb空間分配給核心,這些在前文中都已經介紹過了。
使用者使用的剩下2gb或3gb的記憶體空間稱為使用者空間。在使用者空間裡,也有許多位址區間有特殊的地位,一般來講,應用程式使用的記憶體空間裡有如下「預設」的區域。
堆:堆是用來容納應用程式動態分配的記憶體區域,當程式使用malloc或new分配記憶體時,得到的記憶體來自堆裡。堆會在10.3節詳細介紹。堆通常存在於棧的下方(低位址方向),在某些時候,堆也可能沒有固定統一的儲存區域。堆一般比棧大很多,可以有幾十至數百兆位元組的容量。
可執行檔案映像:這裡儲存著可執行檔案在記憶體裡的映像,在第6章已經提到過,由裝載器在裝載時將可執行檔案的記憶體讀取或對映到這裡。在此不再詳細說明。
保留區:保留區並不是乙個單一的記憶體區域,而是對記憶體中受到保護而禁止訪問的記憶體區域的總稱,例如,大多數作業系統裡,極小的位址通常都是不允許訪問的,如null。通常c語言將無效指標賦值為0也是出於這個考慮,因為0位址上正常情況下不可能有有效的可訪問資料。下圖是linux下程序位址空間模型:
在圖中,有乙個沒有介紹的區域:「動態鏈結庫對映區」,這個區域用於對映裝載的動態鏈結庫。在linux下,如果可執行檔案依賴其他共享庫,那麼系統就會為它在從0x40000000開始的位址分配相應的空間,並將共享庫載入到該空間。
圖中的箭頭標明了幾個大小可變的區的尺寸增長方向,在這裡可以清晰地看出棧向低位址增長,堆向高位址增長。當棧或堆現有的大小不夠用時,它將按照圖中的增長方向擴大自身的尺寸,直到預留的空間被用完為止。
在接下來的兩節中,會詳細介紹上述幾個區域中的棧和堆,讓讀者對應用程式執行時記憶體的狀況有乙個更加深入的理解。
q&aq:我寫的程式常常出現「段錯誤(segment fault)」或者「非法操作,該記憶體位址不能read/write」的錯誤資訊,這是怎麼回事?
a:這是典型的非法指標解引用造成的錯誤。當指標指向乙個不允許讀或寫的記憶體位址,而程式卻試圖利用指標來讀或寫該位址的時候,就會出現這個錯誤。在linux或windows的記憶體布局中,有些位址是始終不能讀寫的,例如0位址。還有些位址是一開始不允許讀寫,應用程式必須事先請求獲取這些位址的讀寫權,或者某些位址一開始並沒有對映到實際的物理記憶體,應用程式必須事先請求將這些位址對映到實際的實體地址(commit),之後才能夠自由地讀寫這片記憶體。當乙個指標指向這些區域的時候,對它指向的記憶體進行讀寫就會引發錯誤。造成這樣的最普遍原因有兩種:
程式設計師將指標初始化為null,之後卻沒有給它乙個合理的值就開始使用指標。
程式設計師沒有初始化棧上的指標,指標的值一般會是隨機數,之後就直接開始使用指標。
因此,如果你的程式出現了這樣的錯誤,請著重檢查指標的使用情況。
程序位址空間
這篇文章應該不能說是原創的,這裡的記錄都是我通過閱讀整理來的,並沒有太多的自己的想法。資料 現代作業系統 之所以去了解位址空間也是因為在學習dll的時候看到要將dll對映到程式的位址空間,不甚明了所以去查詢相關的資料。位址空間其實很好理解 當然針對早期的機器 早期的機器是沒有ram,rom,cach...
程序位址空間
kernel筆記 程序位址空間 2013 09 03 09 53 49 分類 linux 下圖是x86 64下linux程序的預設記憶體布局形式 下面逐一分析以上各個位址段的含義。text 段 段,從虛擬記憶體位址00400000開始,使用pmap 可以檢視到,這個位址是固定的 linux pmap...
程序位址空間
程序位址空間 1.可執行檔案 的記憶體對映,稱為 段 2.可執行檔案的已初始化全域性變數的記憶體對映,稱為資料段 3.包含未初始化的全域性變數,也就是bss段的零頁的記憶體對映 4.用於程序使用者控制項棧的零頁的記憶體對映 5.任何記憶體對映檔案 6.任何共享記憶體段 7.任何匿名的記憶體對映,比如...