溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++程序的內存分區(qū)有哪些

發(fā)布時間:2022-03-04 14:21:08 來源:億速云 閱讀:145 作者:小新 欄目:開發(fā)技術

小編給大家分享一下C++程序的內存分區(qū)有哪些,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

    C++程序在運行時所占用的內存區(qū)域,一般可分為棧內存區(qū)、堆內存區(qū)、全局/靜態(tài)內存區(qū)、文字常量內存區(qū)及程序代碼區(qū)5大分區(qū):

    C++程序的內存分區(qū)有哪些

    下面使用日常開發(fā)中的編程實例,詳細介紹一下這5個分區(qū),以便大家能更深刻的理解這5大內存分區(qū)。

    1、棧內存區(qū)

    棧內存區(qū)是我們用的最多的分區(qū),只要有函數(shù)的地方都會使用到這個分區(qū)。棧分區(qū)是用來存放函數(shù)參數(shù)及函數(shù)局部變量值的內存區(qū),是由編譯器在編譯時自動分配和釋放的。

    函數(shù)中的參數(shù)與函數(shù)中的局部變量占用的內存是代碼執(zhí)行到函數(shù)(進入函數(shù))是分配的,在離開時函數(shù)時這些內存會自動被釋放。下面從下面幾個簡單的實例來更進一步地認識棧內存。

    1.1、調用函數(shù)時通過棧來傳遞函數(shù)的參數(shù)值       

    調用函數(shù)時時通過棧傳遞參數(shù)值的,即在調用函數(shù)之前要將函數(shù)的參數(shù)值依次壓入到棧上,然后再去call被調用函數(shù)的。這點從匯編代碼上可以清晰地看出來。比如下面一段簡單的實現(xiàn)兩數(shù)相加的代碼:

    // 被調用函數(shù)
    int AddNum(int a, int b)
    {
        int nSum = a + b;
        return nSum;
    }
     
     
    // 調用內調用函數(shù)的實例代碼
    int a = 7;
    int b = 8;
     
    int  nSum = AddNum(a, b);

    可以在VS中查看上述C++代碼對應的匯編代碼。具體的做法是,將上述代碼拷貝到VS中,啟動VS調試,在鼠標右鍵單擊顯示的右鍵菜單中點擊“轉到反匯編”區(qū)查看C++代碼對應的匯編代碼:

    C++程序的內存分區(qū)有哪些

    從上述匯編代碼可以看出,在調用AddNum函數(shù)之前,將要傳入的參數(shù)a和參數(shù)b的值先壓到棧上,然后再去call AddNum函數(shù)。作為被調函數(shù)的AddNum會從棧上讀取傳入的參數(shù)內容。

    1.2、線程占用的棧內存是有上限的

    線程占用的棧內存是有上限的,可以在創(chuàng)建線程時指定棧空間的大小。在Windows上,線程默認的棧空間是1MB。線程在某一時刻的函數(shù)調用堆棧中的所有函數(shù)占用的??臻g總和,就是當前時刻的線程占用的棧內存。

    進入函數(shù)時會將該函數(shù)的??臻g累計到所在線程的??臻g占用內存數(shù)上(函數(shù)內部申請存放局部變量的??臻g),離開函數(shù)則會釋放它占用的??臻g,就會將所在線程占用的棧內存數(shù)上減掉函該函數(shù)占用的空間。如果當前線程占用的??臻g大于線程的上限時(一般是在進入一個函數(shù)時觸發(fā)),則會報出“stack overflow”的棧溢出異常:

    C++程序的內存分區(qū)有哪些

    程序會發(fā)生崩潰。

    這里有一點需要說明一下,在某個函數(shù)中使用了switch...case語句,語句中包含了多個case分支,在這些分支中定義了一些局部變量,雖然這些局部變量的生命周期只位于case子句中,但是都是直接算在所在函數(shù)的棧空間上的,是剛執(zhí)行進函數(shù)就分配好了,即便當前還沒運行到對應的case子句中,即便這些case子句的局部變量的生命周期僅在case子句內!

    2、堆內存區(qū)

    堆內存也是我們最常用的內存區(qū),因為每個線程的棧內存是有限的,我們一般將大部分數(shù)據(jù)要放置在堆內存中。

    在C++中,malloc/new申請的內存都是從堆內存上分配的,用完后由free/delete區(qū)釋放的。如果沒有釋放堆內存,則程序結束時由操作系統(tǒng)統(tǒng)一回收。

    堆內存的管理比棧內存要復雜的多,如果是堆內存異常導致的崩潰,比棧內存異常(比如內存越界引起內存訪問為例)導致的崩潰,要難查的多。

    如果malloc/new來的內存在用完后沒有釋放,則會導致內存泄露,如果頻繁執(zhí)行的代碼中有內存泄露則是致命的,因為隨著程序的運行時間的加長,會產(chǎn)生越來越多的內存泄露,如果將所屬進程虛擬內存耗盡,會產(chǎn)生“Out of memory”的異常:

    C++程序的內存分區(qū)有哪些

     程序直接閃退崩潰。

    3、全局/靜態(tài)內存區(qū)

    全局變量和靜態(tài)變量的內存就是在該區(qū)上分配的,全局變量和靜態(tài)變量的生命周期也是一樣的,都是在程序啟動時分配內存的,在程序退出時釋放內存的。

    全局變量一般會使用extern關鍵字來聲明,比如:

    extern int m_nClientId;

    而靜態(tài)變量則是使用static關鍵字來聲明:

    static int nCount;

    全局變量和靜態(tài)變量都要求在定義的時候要初始化,注意此處講的定義是和聲明是相對應的概念。全局變量和靜態(tài)變量的區(qū)別在于,全局變量的作用域更廣,整個模塊中都能使用。靜態(tài)變量則因其定義的位置不同有不同的作用域。

    可以在函數(shù)中定義靜態(tài)變量,也可以在類中定義靜態(tài)成員變量。函數(shù)中定義的靜態(tài)變量只能在函數(shù)中被訪問,類中定義的靜態(tài)變量則可以在類外部使用“類名::靜態(tài)成員變量名”去訪問。

    4、文字常量區(qū)

    該分區(qū)是用來存放常量值,如常量字符串等,比如如下的字符串常量:(將字符串常量的地址賦值給指針p):

    char* p = ”this is a test.”;

    該字符串占用的內存地址就是文字常量區(qū)內存上的。

     該部分內存中的內容是固定的常量,是不允許修改的,程序結束后由操作系統(tǒng)統(tǒng)一回收。這部分內容比較簡單,沒什么要講的。

    5、程序代碼區(qū)

    前面說的內存都是數(shù)據(jù)段的內存,是用來存放程序運行中的各種數(shù)據(jù)的;該部分的內存是代碼段的內存,是用來存放程序二進制代碼的。

    數(shù)據(jù)段的內存地址和代碼段指令的地址,完全是兩個概念,不能混為一談。比如某個變量的內存地址是數(shù)據(jù)段的地址:

    C++程序的內存分區(qū)有哪些

    某條匯編指令的地址,則是代碼段的地址:

    C++程序的內存分區(qū)有哪些

    是兩個完全不搭嘎的地址,一定要區(qū)分開來。

    以上是“C++程序的內存分區(qū)有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業(yè)資訊頻道!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

    c++
    AI