大內高手 記憶體模型

2021-05-24 12:05:36 字數 3653 閱讀 4200

大內高手

—記憶體模型

作者****:李先靜

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的記憶體模型,或許不能讓你大幅度提高程式設計能力,但是作為乙個基本知識點應該熟悉。坐火車外出旅行時,即時你對沿途的地方一無所知,仍然可以到達目標地。但是你對整個路途都很比較清楚的話,每到乙個站都知道自己在 知道當地的風土人情,對比一下所見所想,旅程可...