1. 程式人生 > >C語言中記憶體分佈及程式執行中(BSS段、資料段、程式碼段、堆疊)

C語言中記憶體分佈及程式執行中(BSS段、資料段、程式碼段、堆疊)

BSS段:(bss segment)通常是指用來存放程式中未初始化的全域性變數的一塊記憶體區域。BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態記憶體分配。

資料段 :資料段(data segment)通常是指用來存放程式中 已初始化 的 全域性變數 的一塊記憶體區域。資料段屬於靜態記憶體分配。 
程式碼段: 程式碼段(code segment/text segment)通常是指用來存放 程式執行程式碼 的一塊記憶體區域。這部分割槽域的大小在程式執行前就已經確定,並且記憶體區域通常屬於 只讀 , 某些架構也允許程式碼段為可寫,即允許修改程式。在程式碼段中,也有可能包含一些 只讀的常數變數 ,例如字串常量等。程式段為程式程式碼在記憶體中的對映.一個程式可以在記憶體中多有個副本. 堆(heap) :堆是用於存放程序執行中被動態分配的記憶體段,它的大小並不固定,可動態擴張或縮減。當程序呼叫malloc/free等函式分配記憶體時,新分配的記憶體就被動態新增到堆上(堆被擴張)/釋放的記憶體從堆中被剔除(堆被縮減) 棧(stack) :棧又稱堆疊, 存放程式的 區域性變數 (但不包括static宣告的變數, static 意味著 在資料段中 存放變數)。除此以外,在函式被呼叫時,棧用來傳遞引數和返回值。由於棧的先進先出特點,所以棧特別方便用來儲存/恢復呼叫現場。儲動態記憶體分配,需要程式設計師手工分配,手工釋放 下圖是APUE中的一個典型C記憶體空間分佈圖

 例如:

#include <stdio.h>

int g1=0, g2=0, g3=0;

int max(int i)
{
    int m1=0,m2,m3=0,*p_max;
    static n1_max=0,n2_max,n3_max=0;
     p_max = (int*)malloc(10);
    printf("列印max程式地址\n");
    printf("in max: 0x%08x\n\n",max);
    printf("列印max傳入引數地址\n");
    printf("in max: 0x%08x\n\n",&i);
    printf("列印max函式中靜態變數地址\n");
    printf("0x%08x\n",&n1_max); //列印各本地變數的記憶體地址
    printf("0x%08x\n",&n2_max);
    printf("0x%08x\n\n",&n3_max);
    printf("列印max函式中區域性變數地址\n");
    printf("0x%08x\n",&m1); //列印各本地變數的記憶體地址
    printf("0x%08x\n",&m2);
    printf("0x%08x\n\n",&m3);
    printf("列印max函式中malloc分配地址\n");
    printf("0x%08x\n\n",p_max); //列印各本地變數的記憶體地址

    if(i) return 1;
    else return 0;
}

int main(int argc, char **argv)
{
    static int s1=0, s2, s3=0;
    int v1=0, v2, v3=0;
    int *p;    
    p = (int*)malloc(10);

    printf("列印各全域性變數(已初始化)的記憶體地址\n");
    printf("0x%08x\n",&g1); //列印各全域性變數的記憶體地址
    printf("0x%08x\n",&g2);
    printf("0x%08x\n\n",&g3);
    printf("======================\n");
    printf("列印程式初始程式main地址\n");
    printf("main: 0x%08x\n\n", main);
    printf("列印主參地址\n");
    printf("argv: 0x%08x\n\n",argv);
    printf("列印各靜態變數的記憶體地址\n");
    printf("0x%08x\n",&s1); //列印各靜態變數的記憶體地址
    printf("0x%08x\n",&s2);
    printf("0x%08x\n\n",&s3);
    printf("列印各區域性變數的記憶體地址\n");
    printf("0x%08x\n",&v1); //列印各本地變數的記憶體地址
    printf("0x%08x\n",&v2);
    printf("0x%08x\n\n",&v3);
    printf("列印malloc分配的堆地址\n");
    printf("malloc: 0x%08x\n\n",p);
    printf("======================\n");
    max(v1);
    printf("======================\n");
    printf("列印子函式起始地址\n");
    printf("max: 0x%08x\n\n",max);
    return 0;
}

 列印結果:

可以大致檢視整個程式在記憶體中的分配情況:
可以看出,傳入的引數,區域性變數,都是在棧頂分佈,隨著子函式的增多而向下增長.
函式的呼叫地址(函式執行程式碼),全域性變數,靜態變數都是在分配記憶體的低部存在,而malloc分配的堆則存在於這些記憶體之上,並向上生長.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在作業系統中,一個程序就是處於執行期的程式(當然包括系統資源),實際上正在執行的程式程式碼的活標本。那麼程序的邏輯地址空間是如何劃分的呢?

引用:

圖1做了簡單的說明(Linux系統下的)


左邊的是UNIX/LINUX系統的執行檔案,右邊是對應程序邏輯地址空間的劃分情況。



首先是堆疊區(stack),堆疊是由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。棧的申請是由系統自動分配,如在函式內部申請一個區域性變數 int h,同時判別所申請空間是否小於棧的剩餘空間,如若小於的話,在堆疊中為其開闢空間,為程式提供記憶體,否則將報異常提示棧溢位。    
其次是堆(heap),堆一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由OS回收 。注意它與資料結構中的堆是兩回事,分配方式倒是類似於連結串列。堆的申請是由程式設計師自己來操作的,在C中使用malloc函式,而C++中使用new運算子,但是堆的申請過程比較複雜:當系統收到程式的申請時,會遍歷記錄空閒記憶體地址的連結串列,以求尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點連結串列中刪除,並將該結點的空間分配給程式,此處應該注意的是有些情況下,新申請的記憶體塊的首地址記錄本次分配的記憶體塊大小,這樣在delete尤其是delete[]時就能正確的釋放記憶體空間。
接著是全域性資料區(靜態區) (static),全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域, 未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。 另外文字常量區,常量字串就是放在這裡,程式結束後有系統釋放。
最後是程式程式碼區,放著函式體的二進位制程式碼。

舉例說明一下:
int a = 0;                   //全域性初始化區 


char *p1;                //全域性未初始化區 


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); //分配得來得10和20位元組的區域就在堆區。 

        strcpy(p1, "123456");    //123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。

        return 0;

}

相關推薦

C語言記憶體分佈程式執行(BSS資料程式碼堆疊

BSS段:(bss segment)通常是指用來存放程式中未初始化的全域性變數的一塊記憶體區域。BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態記憶體分配。 資料段 :資料段(data segment)通常是指用來存放程式中 已初始化 

C語言程式設計:圖書管理系統(超詳細有登入系統,附程式碼和試驗報告

C課程設計——圖書管理系統 1、題目意義 圖書館,作為文獻的聚集地和展示平臺,常常扮演著引領文化前進的角色,是每個大學不可或缺的基礎設施,而圖書管理系統則是一個圖書館能夠正常運轉的關鍵。本次課程設計使用C語言製作程式來實現圖書的登記,刪除,查詢,瀏覽以及讀者的借

C語言記憶體分佈

先認識記憶體中的幾個區,下面的區都在記憶體中,意味著掉電會丟失。但是這不意味著記憶體條裡面真的是這樣,包括作業系統的分頁都只是對記憶體的一種管理方式,或者說是虛擬的邏輯管理。 棧區(stack):由編譯器自動分配釋放,存放函式的引數值、區域性變數、返回值等。其

c語言五大記憶體分割槽-(堆,棧,全域性/靜態儲存區,自由儲存區,程式碼與可執行程式的三-(Text,DateBss

一、c語言五大記憶體分割槽 棧區(stack):存放函式形參和區域性變數(auto型別),由編譯器自動分配和釋放 堆區(heap):該區由程式設計師申請後使用,需要手動釋放否則會造成記憶體洩漏。如果程式設計師沒有手動釋放,那麼程式結束時可能由OS回收。

C語言記憶體分配函式malloc/ calloc/ realloc記憶體釋放free

前言: 記憶體區域劃分與分配: 1、棧區(stack)——程式執行時由編譯器自動分配,存放函式的引數值,區域性變數的值等,程式結束時由編譯器自動釋放。 2、堆區(heap) —— 在記憶體開闢另一塊儲存區域。一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可

c語言記憶體資料以二進位制形式寫入檔案 檔案資料表現形式

最近有在寫關於將記憶體中的資料寫入檔案的程式,當程式執行後,卻發現檔案中的位元組資料有些難以理解。思考後發現了其中的道理。 程式碼如下: #include<stdio.h> #include<stdlib.h> struct BlockInfo { bool is

C# 程式執行的流程控制

1、C#之流程控制語句:計算機程式執行的控制流程由三種基本的控制結構控制,即順序結構,選擇結構,迴圈結構。 1) 順序結構:從上到下,按照書寫順序執行每一條語句,不會發生跳躍。 程式碼段1; // 先執行程式碼段1 程式碼段2; // 接著執行程式碼段2 ... 2)選擇結構:對

C語言除錯記憶體訪問出錯而引起的程式崩潰問題

在寫程式碼的時候,經常碰到由於記憶體訪問出錯而導致程式崩潰。當代碼量比較多的時候,根本不知道程式錯在哪裡,只能不斷猜測程式碼出錯的地方,將其註釋掉還會不會出現程式崩潰,這種方法雖然最後也能找到問題所在,但是會耗費大量時間。 linux下除錯通常會生成core d

C語言實現簡易的shell程式,支援多重管道重定向

1 簡介 用C語言實現的一個簡易的shell,能夠接受使用者輸入的命令並執行操作,支援多重管道及重定向。 程式執行後,會模擬shell用綠色字型顯示當前的使用者名稱、主機名和路徑,等待使用者輸入命令。程式逐次讀取使用者輸入的指令後,將指令按空

.net C# web程式執行錯誤日誌寫入文字檔案

網上找的原始碼,自己根據實際情況進行了修改,能將日誌儲存在發不出來的web程式根目錄下的ErrorLog資料夾內。 #region 建立錯誤日誌 ///-------------------------------------

C語言:利用指標編寫程式,定義一個3行3列的二維陣列,並在程式對其進行賦值,陣列元素的型別不限,輸出該二維陣列以及各行的均值

題目來源:大工慕課 連結 作者:Caleb Sung 題目要求 利用指標編寫程式,定義一個3行3列的二維陣列,並在程式中對其進行賦值,陣列元素的型別不限,輸出該二維陣列以及各行的均值,各行

c語言的起源特點c程式的基本結構

今天水一波,記錄一些概念性的知識,嘿嘿嘿C語言的起源CPL語言(Combined Programming Language)1963年英國的劍橋大學推出了CPL語言,較接近硬體,難懂,實現難。BCPL語言(Basic CPL)1967年英國劍橋大學的Matin Richard

C語言動態記憶體分配:(一malloc/free的實現malloc實際分配/釋放的記憶體

一、malloc/free概述 malloc是在C語言中用於在程式執行時在堆中進行動態記憶體分配的庫函式。free是進行記憶體釋放的庫函式。 1、函式原型 #include <stdlib.h> void *malloc( size_t size

c語言堆與棧記憶體分配

原文:http://www.cnblogs.com/TonyEwsn/archive/2010/01/29/1659496.html 格式和部分內容稍作修改。 在計算機領域,堆疊是一個不容忽視的概念,我們編寫的C語言程式基本上都要用到。但對於很多的初學著來說,堆疊是

c語言分配記憶體方式有哪些?c語言常見的記憶體錯誤有哪些?

記憶體分配方式有三種:   1、從靜態儲存區域分配。記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個執行期間都存在。例如全域性變數,static變數。   2、在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放

C++】C++幾種測試程式執行時間的方法

關於C++中計算時間的一些總結 一、使用GetTickCount()函式 GetTickCount()是一個函式,可以把它理解為打點計時器。GetTickCount()是通過計算從函式開始執行計時

黑馬程式設計師—C語言筆記—記憶體剖析

一、進位制 1、定義:是一種計數的方式,數值的表示形式。 2、常用的4種進位制: 二進位制以0b/0B開頭如int num1 = 0b1100; 八進位制以0開頭如int num2 = 014; 十進位制如 int num3 = 12; 十六進位制以0x/0X開頭如int num4=0xc;

C語言setpriority()函式:設定程式程序執行優先權

相關函式:getpriority, nice 標頭檔案:#include <sys/time.h>    #include <sys/resource.h> 定義函式:int setpriority(int which, int who, int p

c++常用的計算程式執行時間的方法

方法1: 計時函式是clock(),而與其相關的資料型別是clock_t(標頭檔案是time.h)。函式定義原型為:clock_t clock(void); 這個函式返回從“開啟這個程式程序”到“程式中呼叫clock()函式”時之間的CPU時鐘計時單元(clock t

C語言--第0次作業(助教修訂)

abc ron lan sdn 留下 evc 存在 這樣的 職業規劃 一、首先要做的事   1. 建博客     在博客園[https://www.cnblogs.com/]申請博客。     關註牛老師的博客[http://www.cnblogs.com/c-progra