https://blog.csdn.net/weixin_39540568/article/details/88363212
問題引出:在看一些資料博客的時候說線程共享同一個進程的代碼段和數據段,又有說法是代碼段和數據段在可執行文件中加載,比較疑惑,下面稍微具體的整理一下。
在解釋原因前我們先看一下一個由C/C++編譯的程序占用的內存分為幾個部分:
#include <iostream> #include <stdio.h> using std::endl; using std::cout; char *p1; //全局未初始化區 int a = 0; //全局初始化區 int main() { int b; //棧 char s[] = "abc";//棧 char *p2;//棧 char *p3 = "123456";// 123456\0在常量區,p3在棧上。 static int c = 0; //全局(靜態)初始化區 p1 = (char *)malloc(10);//堆 p2 = (char *)malloc(20);//椎 int *p5 = new int[10];//椎 cout << "&p3=======" << &p3 << endl; cout << "&p2=======" << &p2 << endl; cout << "&s========" << &s << endl; cout << "&b========" << &b << endl; cout << "p5========" << p5 << endl; cout << "&c========" << &c << endl; cout << "&p1=======" << &p1 << endl; cout << "&a========" << &a << endl; cout << "sizeof(p1)========" << sizeof(p1) << endl; cout << "sizeof(&a)========" << sizeof(&a) << endl; cout << "sizeof(&c)========" << sizeof(&c) << endl; cout << "sizeof(p5)========" << sizeof(p5) << endl; return 0; }
MacOS 10.14.6的運行結果:
動&靜
一個程序被加載到內存中,這塊內存首先就存在兩種屬性:靜態分配內存和動態分配內存。
靜態分配內存:是在程序編譯和鏈接時就確定好的內存。
動態分配內存:是在程序加載、調入、執行的時候分配/回收的內存。
Text & Data & Bss(代碼段、初始化數據、未初始化數據)
-
.text: 也稱為代碼段(Code),用來存放程序執行代碼,同時也可能會包含一些常量(如一些字符串常量等)。該段內存為靜態分配,只讀(某些架構可能允許修改)。
這塊內存是共享的,當有多個相同進程(Process)存在時,共用同一個text段。 -
.data: 也有的地方叫GVAR(global value),用來存放程序中已經初始化的非零全局變量。靜態分配。
- data又可分為讀寫(RW)區域和只讀(RO)區域。
-> RO段保存常量所以也被稱為.constdata
eg const數據
-> RW段則是普通非常全局變量,靜態變量就在其中
- data又可分為讀寫(RW)區域和只讀(RO)區域。
-
.bss: 存放程序中未初始化的和零值全局變量。靜態分配,在程序開始時通常會被清零。
-
其中.bss和.data合稱為數據段
text和data段都在可執行文件中,由系統從可執行文件中加載;而bss段不在可執行文件中,由系統初始化。
這三段內存就組成了我們編寫的程序的本體,但是一個程序運行起來,還需要更多的數據和數據間的交互,否則這個程序就是死的,無用的。所以我們還需要為更多的數據和數據交互提供一塊內存——堆棧。
堆棧(Heap& Stack)
堆和棧都是動態分配內存,兩者空間大小都是可變的。
-
Stack: 棧,存放Automatic Variables,按內存地址由高到低方向生長,其最大大小由編譯時確定,速度快,但自由性差,最大空間不大。保存程序中的局部變量(也就是在代碼塊中的變量)這樣的變量伴隨着函數的調用和終止,在內存中也相應的增加或者減少。這樣的變量在創建時期按順序加入,在消亡的時候按相反的順序移除。 (來自另一片博客解釋:由編譯器自動分配釋放,存放函數的參數的值,局部變量的值等。在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區 域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是2M(也有的是1M,總之是一個編譯時就確定的常數), 如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小)
-
Heap: 堆,自由申請的空間,按內存地址由低到高方向生長,其大小由系統內存/虛擬內存上限決定,速度較慢,但自由性大,可用空間大。 動態分配的內存在調用malloc()或者相關函數產生,在調用free()時釋放,由程序員而不是一系列固定的規則內存持續時間,因此內存塊可在一個函數中創建,在另一個函數中釋放。由於這點,動態內存分配所使用的部分可能就碎片,也就是說:在活動的內存塊之間散布着未使用的內存片。動態分配內存往往要比棧分配的內存慢(一般由程序員分配釋放,若程序員不釋放,程序結束時可能由系統回收 。它與數據結構中的堆是兩回事。堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表 的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。)
-
每個線程都會有自己的棧,但是堆空間是共用的。
-
-
圖解
在 sw-at 這張圖中所示內存空間,地址由下往上增長,分別標示了 .text、.data、.bss、stack和heap的內存分部情況。
我們可以看到:
- text、data(gvar)、bss 在內存中地址較低低的位置(low level address),而堆棧則在相對較搞的位置。
- 堆(Heap)往高地址方向生長,棧(Stack)往低地址方向生長。