日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Linux内存模型

發(fā)布時(shí)間:2025/6/15 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux内存模型 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

了解linux的內(nèi)存模型,或許不能讓你大幅度提高編程能力,但是作為一個(gè)基本知識(shí)點(diǎn)應(yīng)該熟悉。坐火車外出旅行時(shí),即時(shí)你對(duì)沿途的地方一無(wú)所知,仍然可以到達(dá)目標(biāo)地。但是你對(duì)整個(gè)路途都很比較清楚的話,每到一個(gè)站都知道自己在哪里,知道當(dāng)?shù)氐娘L(fēng)土人情,對(duì)比一下所見(jiàn)所想,旅程可能更有趣一些。?

類似的,了解linux的內(nèi)存模型,你知道每塊內(nèi)存,每個(gè)變量,在系統(tǒng)中處于什么樣的位置。這同樣會(huì)讓你心情愉快,知道這些,有時(shí)還會(huì)讓你的生活輕更松些。看看變量的地址,你可以大致斷定這是否是一個(gè)有效的地址。一個(gè)變量被破壞了,你可以大致推斷誰(shuí)是犯罪嫌疑人。?

Linux的內(nèi)存模型,一般為:

地址

作用

說(shuō)明

>=0xc000 0000

內(nèi)核虛擬存儲(chǔ)器

用戶代碼不可見(jiàn)區(qū)域

<0xc000 0000

Stack(用戶棧)

ESP指向棧頂

?

?

?

空閑內(nèi)存

>=0x4000 0000

文件映射區(qū)

?

<0x4000 0000

?

?

?

空閑內(nèi)存

?

?

Heap(運(yùn)行時(shí)堆)

通過(guò)brk/sbrk系統(tǒng)調(diào)用擴(kuò)大堆,向上增長(zhǎng)。

?

.data.bss(讀寫段)

從可執(zhí)行文件中加載

>=0x0804 8000

.init.text.rodata(只讀段)

從可執(zhí)行文件中加載

<0x0804 8000

保留區(qū)域

?

?

很多書上都有類似的描述,本圖取自于《深入理解計(jì)算機(jī)系統(tǒng)》p603,略做修改。本圖比較清析,很容易理解,但仍然有兩點(diǎn)不足。下面補(bǔ)充說(shuō)明一下:

?

1.???????? 第一點(diǎn)是關(guān)于運(yùn)行時(shí)堆的

為說(shuō)明這個(gè)問(wèn)題,我們先運(yùn)行一個(gè)測(cè)試程序,并觀察其結(jié)果:

#include <stdio.h> intmain(intargc, char* argv[]) { int first = 0; int* p0 = malloc(1024); int* p1 = malloc(1024 * 1024); int* p2 = malloc(512 * 1024 * 1024 ); int* p3 = malloc(1024 * 1024 * 1024 ); printf("main=%p print=%p/n", main, printf); printf("first=%p/n", &first); printf("p0=%p p1=%p p2=%p p3=%p/n", p0, p1, p2, p3); getchar(); return 0; }

運(yùn)行后,輸出結(jié)果為:

main=0x8048404 print=0x8048324

first=0xbfcd1264

p0=0x9253008 p1=0xb7ec0008 p2=0x97ebf008 p3=0x57ebe008

? mainprint兩個(gè)函數(shù)是代碼段(.text)的,其地址符合表一的描述。

l???????? first是第一個(gè)臨時(shí)變量,由于在first之前還有一些環(huán)境變量,它的值并非0xbfffffff,而是0xbfcd1264,這是正常的。

l???????? p0是在堆中分配的,其地址小于0x4000 0000,這也是正常的。

l???????? p1p2也是在堆中分配的,而其地址竟大于0x4000 0000,與表一描述不符。?

原因在于:運(yùn)行時(shí)堆的位置與內(nèi)存管理算法相關(guān),也就是與malloc的實(shí)現(xiàn)相關(guān)。關(guān)于內(nèi)存管理算法的問(wèn)題,我們?cè)诤罄^文章中有詳細(xì)描述,這里只作簡(jiǎn)要說(shuō)明。在glibc實(shí)現(xiàn)的內(nèi)存管理算法中,Malloc小塊內(nèi)存是在小于0x4000 0000的內(nèi)存中分配的,通過(guò)brk/sbrk不斷向上擴(kuò)展,而分配大塊內(nèi)存,malloc直接通過(guò)系統(tǒng)調(diào)用mmap實(shí)現(xiàn),分配得到的地址在文件映射區(qū),所以其地址大于0x4000 0000?

maps文件中可以清楚的看到一點(diǎn):

00514000-00515000 r-xp 00514000 00:00 0

00624000-0063e000 r-xp 00000000 03:01 718192???? /lib/ld-2.3.5.so

0063e000-0063f000 r-xp 00019000 03:01 718192???? /lib/ld-2.3.5.so

0063f000-00640000 rwxp 0001a000 03:01 718192???? /lib/ld-2.3.5.so

00642000-00766000 r-xp 00000000 03:01 718193???? /lib/libc-2.3.5.so

00766000-00768000 r-xp 00124000 03:01 718193???? /lib/libc-2.3.5.so

00768000-0076a000 rwxp 00126000 03:01 718193???? /lib/libc-2.3.5.so

0076a000-0076c000 rwxp 0076a000 00:00 0

08048000-08049000 r-xp 00000000 03:01 1307138??? /root/test/mem/t.exe

08049000-0804a000 rw-p 00000000 03:01 1307138??? /root/test/mem/t.exe

09f5d000-09f7e000 rw-p 09f5d000 00:00 0????????? [heap]

57e2f000-b7f35000 rw-p 57e2f000 00:00 0

b7f44000-b7f45000 rw-p b7f44000 00:00 0

bfb2f000-bfb45000 rw-p bfb2f000 00:00 0????????? [stack]

?

2.???????? 第二是關(guān)于多線程的。

現(xiàn)在的應(yīng)用程序,多線程的居多。表一所描述的模型無(wú)法適用于多線程環(huán)境。按表一所述,程序最多擁有上G的棧空間,事實(shí)上,在多線程情況下,能用的棧空間是非常有限的。為了說(shuō)明這個(gè)問(wèn)題,我們?cè)倏戳硗庖粋€(gè)測(cè)試:

#include <stdio.h> #include <pthread.h> void* thread_proc(void* param) { int first = 0; int* p0 = malloc(1024); int* p1 = malloc(1024 * 1024); printf("(0x%x): first=%p/n", pthread_self(), &first); printf("(0x%x): p0=%p p1=%p /n", pthread_self(), p0, p1); return 0; } #define N 5 intmain(intargc, char* argv[]) { intfirst = 0; inti= 0; void* ret = NULL; pthread_t tid[N] = {0}; printf("first=%p/n", &first); for(i = 0; i < N; i++) { pthread_create(tid+i, NULL, thread_proc, NULL); } for(i = 0; i < N; i++) { pthread_join(tid[i], &ret); } return 0; }

運(yùn)行后,輸出結(jié)果為:

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

?

我們看一下:

主線程與第一個(gè)線程的棧之間的距離:0xbfd3d35c - 0xb7f2c454=0x7e10f08=126M

第一個(gè)線程與第二個(gè)線程的棧之間的距離:0xb7f2c454 - 0xb752b454=0xa01000=10M

其它幾個(gè)線程的棧之間距離均為10M

也就是說(shuō),主線程的棧空間最大為126M,而普通線程的棧空間僅為10M,超這個(gè)范圍就會(huì)造成棧溢出。

系統(tǒng)為進(jìn)程分配數(shù)據(jù)空間有三種形式。

靜態(tài)分配

整塊靜態(tài)分配空間,包括其中的所有數(shù)據(jù)實(shí)體,都是在進(jìn)程創(chuàng)建時(shí)由系統(tǒng)一次性分配的(同時(shí)為UNIX稱為Text的代碼分配空間)。這塊空間在進(jìn)程運(yùn)行期間保持不變。

初始化的和未初始化的實(shí)體分別放在初始化數(shù)據(jù)段和未初始化數(shù)據(jù)段(BSS)。后者和前者不同,在.o文件a.out文件里都不存在(只有構(gòu)架信息),在進(jìn)程的虛擬空間里才展開(kāi)。

extern變量和static變量采用靜態(tài)分配。

在進(jìn)程創(chuàng)建時(shí)做靜態(tài)分配,分配正文(text)段、數(shù)據(jù)段和棧空間。

正文和初始化數(shù)據(jù)是按a.out照樣復(fù)制過(guò)來(lái);未初始化數(shù)據(jù)按構(gòu)架信息展開(kāi),填以0或空;棧空間的大小由鏈接器開(kāi)關(guān)(具體哪個(gè)開(kāi)關(guān)忘了)決定。

棧分配

整個(gè)棧空間已在進(jìn)程創(chuàng)建時(shí)分配好。棧指針SP的初值的設(shè)定,確定了棧空間的大小。鏈接器的某個(gè)開(kāi)關(guān)可以設(shè)定棧空間的大小。在進(jìn)程運(yùn)行期間,棧空間的大小不變。但是,在進(jìn)程剛啟動(dòng)時(shí),棧空間是空的,里面沒(méi)有實(shí)體。在進(jìn)程運(yùn)行期間,對(duì)具體實(shí)體的棧分配是進(jìn)程自行生成(壓棧)和釋放(彈出)實(shí)體,系統(tǒng)并不參與。

auto變量和函數(shù)參數(shù)采用棧分配。

只要壓入的實(shí)體的總長(zhǎng)度不超過(guò)棧空間尺寸,棧分配就與系統(tǒng)無(wú)關(guān)。如果超過(guò)了,就會(huì)引發(fā)棧溢出錯(cuò)誤。

堆分配

當(dāng)進(jìn)程需要生成實(shí)體時(shí),向系統(tǒng)申請(qǐng)分配空間;不再需要該實(shí)體時(shí),可以向系統(tǒng)申請(qǐng)回收這塊空間。

堆分配使用特定的函數(shù)(如malloc()等)或操作符(new)。所生成的實(shí)體都是匿名的,只能通過(guò)指針去訪問(wèn)。

對(duì)實(shí)體來(lái)說(shuō),棧分配和堆分配都是動(dòng)態(tài)分配:實(shí)體都是在進(jìn)程運(yùn)行中生成和消失。而靜態(tài)分配的所有實(shí)體都是在進(jìn)程創(chuàng)建時(shí)全部分配好的,在運(yùn)行中一直存在。

同為動(dòng)態(tài)分配,棧分配與堆分配是很不相同的。前者是在進(jìn)程創(chuàng)建時(shí)由系統(tǒng)分配整塊棧空間,以后實(shí)體通過(guò)壓棧的方式產(chǎn)生,并通過(guò)彈出的方式取消。不管是否產(chǎn)生實(shí)體,產(chǎn)生多少實(shí)體,棧空間總是保持原來(lái)的大小。后者并沒(méi)有預(yù)設(shè)的空間,當(dāng)需要產(chǎn)生實(shí)體時(shí),才向系統(tǒng)申請(qǐng)正好能容納這個(gè)實(shí)體的空間。當(dāng)不再需要該實(shí)體時(shí),可以向系統(tǒng)申請(qǐng)回收這塊空間。因此,堆分配是真正的動(dòng)態(tài)分配。

顯然,堆分配的空間利用率最高。

棧分配和靜態(tài)分配也有共性:整塊空間是在進(jìn)程創(chuàng)建時(shí)由系統(tǒng)分配的。但是,后者同時(shí)分配了所有實(shí)體的空間,而前者在進(jìn)程啟動(dòng)時(shí)是空的。另外,棧上的實(shí)體和數(shù)據(jù)段里的實(shí)體都是有名實(shí)體,可以通過(guò)標(biāo)識(shí)符來(lái)訪問(wèn)。

?

靜態(tài)分配

棧分配

堆分配

整塊空間生成

進(jìn)程創(chuàng)建時(shí)

進(jìn)程創(chuàng)建時(shí)

用一點(diǎn)分配一點(diǎn)

實(shí)體生成時(shí)間

進(jìn)程創(chuàng)建時(shí)

進(jìn)程運(yùn)行時(shí)

進(jìn)程運(yùn)行時(shí)

實(shí)體生成者

操作系統(tǒng)

進(jìn)程

進(jìn)程申請(qǐng)/系統(tǒng)實(shí)施

生命期

永久

臨時(shí)

完全可控

有名/匿名

有名

有名

匿名

訪問(wèn)方式

能以標(biāo)識(shí)訪問(wèn)

能以標(biāo)識(shí)訪問(wèn)

只能通過(guò)指針訪問(wèn)

空間可否回收

不可

不可

可以

?

棧溢出的后果是比較嚴(yán)重的,或者出現(xiàn)Segmentation fault錯(cuò)誤,或者出現(xiàn)莫名其妙的錯(cuò)誤。

總結(jié)

以上是生活随笔為你收集整理的Linux内存模型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。