大內高手
—記憶體模型
作者****:李先靜
2007-7-9 了解
linux
的記憶體模型,或許不能讓你大幅度提高程式設計能力,但是作為乙個基本知識點應該熟悉。坐火車外出旅行時,即時你對沿途的地方一無所知,仍然可以到達目標地。但是你對整個路途都很比較清楚的話,每到乙個站都知道自己在**,知道當地的風土人情,對比一下所見所想,旅程可能更有趣一些。
類似的,了解
linux
的記憶體模型,你知道每塊記憶體,每個變數,在系統中處於什麼樣的位置。這同樣會讓你心情愉快,知道這些,有時還會讓你的生活輕更鬆些。看看變數的位址,你可以大致斷定這是否是乙個有效的位址。乙個變數被破壞了,你可以大致推斷誰是犯罪嫌疑人。
linux
的記憶體模型,一般為:
位址作用
說明》=0xc000 0000
核心虛擬儲存器
使用者**不可見區域
<0xc000 0000
stack
(使用者棧)
esp指向棧頂 ↓
↑空閒記憶體
>=0x4000 0000
檔案對映區
<0x4000 0000
↑ 空閒記憶體
heap(
執行時堆)
通過brk/sbrk
系統呼叫擴大堆,向上增長。
.data
、.bss(
讀寫段)
從可執行檔案中載入
>=0x0804 8000
.init
、.text
、.rodata(
唯讀段)
從可執行檔案中載入
<0x0804 8000
保留區域
很多書上都有類似的描述,本圖取自於《深入理解計算機系統》
p603
,略做修改。本圖比較清析,很容易理解,但仍然有兩點不足。下面補充說明一下:
1.第一點是關於執行時堆的。
為說明這個問題,我們先執行乙個測試程式,並觀察其結果:
<
stdio
.h>
intmain
(int
argc
char
argv)
執行後,輸出結果為:
main=0x8048404 print=0x8048324
first=0xbfcd1264
p0=0x9253008 p1=0xb7ec0008 p2=0x97ebf008 p3=0x57ebe008
lmain
和print
兩個函式是**段
(.text)
的,其位址符合表一的描述。
lfirst
是第乙個臨時變數,由於在
first
之前還有一些環境變數,它的值並非
0xbfffffff
,而是0xbfcd1264
,這是正常的。lp0
是在堆中分配的,其位址小於
0x4000 0000
,這也是正常的。l但
p1和p2也是在堆中分配的,而其位址竟大於
0x4000 0000
,與表一描述不符。
原因在於:執行時堆的位置與記憶體管理演算法相關,也就是與
malloc
的實現相關。關於記憶體管理演算法的問題,我們在後繼文章中有詳細描述,這裡只作簡要說明。在
glibc
實現的記憶體管理演算法中,
malloc
小塊記憶體是在小於
0x4000 0000
的記憶體中分配的,通過
brk/sbrk
不斷向上擴充套件,而分配大塊記憶體,
malloc
直接通過系統呼叫
mmap
實現,分配得到的位址在檔案對映區,所以其位址大於
0x4000 0000。 從
maps
檔案中可以清楚的看到一點:
00514000-00515000 r-xp 00514000 00:00 0
/lib/ld-2.3.5.so
/lib/ld-2.3.5.so
/lib/ld-2.3.5.so
/lib/libc-2.3.5.so
/lib/libc-2.3.5.so
/lib/libc-2.3.5.so
0076a000-0076c000 rwxp 0076a000 00:00 0
/root/test/mem/t.exe
/root/test/mem/t.exe
[heap]
57e2f000-b7f35000 rw-p 57e2f000 00:00 0
b7f44000-b7f45000 rw-p b7f44000 00:00 0
[stack]
2.
第二是關於多執行緒的。
現在的應用程式,多執行緒的居多。表一所描述的模型無法適用於多執行緒環境。按表一所述,程式最多擁有上
g的棧空間,事實上,在多執行緒情況下,能用的棧空間是非常有限的。為了說明這個問題,我們再看另外乙個測試:
<
stdio
.h>
void
thread_proc
(void
param)n
intmain
(int
argc
char
argv);
printf
("first=%p/n"
, &first
);for(i
ini++)
for(ii
ni++)return}
執行後,輸出結果為:
first=0xbfd3d35c
(0xb7f2cbb0): first=0xb7f2c454
(0xb7f2cbb0): p0=0x84d52d8 p1=0xb4c27008
(0xb752bbb0): first=0xb752b454
(0xb752bbb0): p0=0x84d56e0 p1=0xb4b26008
(0xb6b2abb0): first=0xb6b2a454
(0xb6b2abb0): p0=0x84d5ae8 p1=0xb4a25008
(0xb6129bb0): first=0xb6129454
(0xb6129bb0): p0=0x84d5ef0 p1=0xb4924008
(0xb5728bb0): first=0xb5728454
(0xb5728bb0): p0=0x84d62f8 p1=0xb7e2c008
我們看一下
: 主線程與第乙個執行緒的棧之間的距離:
0xbfd3d35c - 0xb7f2c454=0x7e10f08=126m
第乙個執行緒與第二個執行緒的棧之間的距離:
0xb7f2c454 - 0xb752b454=0xa01000=10m
其它幾個執行緒的棧之間距離均為
10m。
也就是說,主線程的棧空間最大為
126m
,而普通執行緒的棧空間僅為
10m,超這個範圍就會造成棧溢位。
棧溢位的後果是比較嚴重的,或者出現
segmentation fault
錯誤,或者出現莫名其妙的錯誤。
大內高手 記憶體模型
大內高手 記憶體模型 了解linux的記憶體模型,或許不能讓你大幅度提高程式設計能力,但是作為乙個基本知識點應該熟悉。坐火車外出旅行時,即時你對沿途的地方一無所知,仍然可以到達目標地。但是你對整個路途都很比較清楚的話,每到乙個站都知道自己在 知道當地的風土人情,對比一下所見所想,旅程可能更有趣一些。...
大內高手 記憶體模型
了解linux的記憶體模型,或許不能讓你大幅度提高程式設計能力,但是作為乙個基本知識點應該熟悉。坐火車外出旅行時,即時你對沿途的地方一無所知,仍然可以到達目標地。但是你對整個路途都很比較清楚的話,每到乙個站都知道自己在 知道當地的風土人情,對比一下所見所想,旅程可能更有趣一些。類似的,了解linux...
大內高手 記憶體模型
大內高手 記憶體模型 作者 李先靜 了解linux的記憶體模型,或許不能讓你大幅度提高程式設計能力,但是作為乙個基本知識點應該熟悉。坐火車外出旅行時,即時你對沿途的地方一無所知,仍然可以到達目標地。但是你對整個路途都很比較清楚的話,每到乙個站都知道自己在 知道當地的風土人情,對比一下所見所想,旅程可...