C++——程序的內存結構


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段則是普通非常全局變量,靜態變量就在其中
  • .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)往低地址方向生長。

memery


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM