1. 程式人生 > >C++ 應用程式 記憶體結構 --- BSS段,資料段,程式碼段,堆記憶體和棧

C++ 應用程式 記憶體結構 --- BSS段,資料段,程式碼段,堆記憶體和棧


二. 在C++中,記憶體分成5個區,他們分別是堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區
1.棧,
就 是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數、函式引數等。
2.堆,就 是那些由new分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式去控制,一般一個new就要對應一個delete。如果程式設計師沒有釋放掉,那麼在 程式結束後,作業系統會自動回收。
3.自由儲存區,就是那些由malloc等分配的記憶體塊,他和堆是十分相似 的,不過它是用free來結束自己的生命的。
4.全域性/靜態儲存區,全域性變數和靜態變數被分配到同一塊記憶體 中,在以前的C語言中,全域性變數又分為初始化的和未初始化的,在C++裡面沒有這個區分了,他們共同佔用同一塊記憶體區。

5.常量 儲存區,這是一塊比較特殊的儲存區,他們裡面存放的是常量,不允許修改(當然,你要通過非正當手段也可以修改)

三. 談談堆與棧的關係與區別
具體地說,現代計算機(序列執行機制),都直接在代 碼底層支援棧的資料結構。這體現在,有專門的暫存器指向棧所在的地址,有專門的機器指令完成資料入棧出棧的操作。這種機制的特點是效率高,支援的資料有 限,一般是整數,指標,浮點數等系統直接支援的資料型別,並不直接支援其他的資料結構。因為棧的這種特點,對棧的使用在程式中是非常頻繁的。對子程式的調 用就是直接利用棧完成的。機器的call指令裡隱含了把返回地址推入棧,然後跳轉至子程式地址的操作,而子程式中的ret指令則隱含從堆疊中彈出返回地址 並跳轉之的操作。C/C++中的自動變數是直接利用棧的例子,這也就是為什麼當函式返回時,該函式的
自動變數自動失效的 原因。 

和棧不同,堆的資料結構並不是由系統(無論是機器系統還是作業系統)支援的,而是由函式庫提供的。基本的 malloc/realloc/free 函式維護了一套內部的堆資料結構。當程式使用這些函式去獲得新的記憶體空間時,這套函式首先試圖從內部堆中尋找可用的記憶體空間,如果沒有可以使用的記憶體空 間,則試圖利用系統呼叫來動態增加程式資料段的記憶體大小,新分配得到的空間首先被組織進內部堆中去,然後再以適當的形式返回給呼叫者。當程式釋放分配的內 存空間時,這片記憶體空間被返回內部堆結構中,可能會被適當的處理(比如和其他空閒空間合併成更大的空閒空間),以更適合下一次記憶體分配申請。這套複雜的分 配機制實際上相當於一個
記憶體分配的緩衝池(Cache),使用這套機制有如下若干原因:
1. 系統呼叫可能不支援任意大小的記憶體分配。有些系統的系統呼叫只支援固定大小及其倍數的記憶體請求(按頁分配);這樣的話對於大量的小記憶體分類來說會造成浪 費。
2. 系統呼叫申請記憶體可能是代價昂貴的。系統呼叫可能涉及使用者態和核心態的轉換。
3. 沒有管理的記憶體分配在大量複雜記憶體的分配釋放操作下很容易造成記憶體碎片。

堆和棧的對比
從以上 知識可知,棧是系統提供的功能,特點是快速高效,缺點是有限制,資料不靈活;而棧是函式庫提供的功能,特點是靈活方便,資料適應面廣泛,但是效率有一定降 低。棧是系統資料結構,對於程序/執行緒是唯一的;堆是函式庫內部資料結構,不一定唯一。不同堆分配的記憶體無法互相操作。棧空間分靜態分配和動態分配兩種。 靜態分配是編譯器完成的,比如自動變數(auto)的分配。動態分配由alloca函式完成。棧的動態分配無需釋放(是自動的),也就沒有釋放函式。為可 移植的程式起見,棧的動態分配操作是不被鼓勵的!堆空間的分配總是動態的,雖然程式結束時所有的資料空間都會被釋放回系統,但是精確的申請記憶體/ 釋放記憶體匹配是良好程式的基本要素。

1.碎片問題:對於堆來講,頻繁的new/delete勢必會造成記憶體空間 的不連續,從而造成大量的碎片,使程式效率降低。對於棧來講,則不會存在這個問題,因為棧是先進後出的佇列,他們是如此的一一對應,以 至於永遠都不可能有一個記憶體塊從棧中間彈出,在他彈出之前,在他上面的後進的棧內容已經被彈出,詳細的可以>參考資料結構,這裡我們就不再一一討論 了。
2.生長方向:對於堆來講,生長方向是向上的,也就是向著記憶體地址增加的方向;對於棧來講,它的生長方向是向下的,是向著記憶體地址減小的方向增長。
3.分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配由 alloca函式進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。
4.分配效率:棧是機器系統提供的資料結構,計算機會在底層對棧提供支援:分配專門的暫存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧 的效率比較高。堆則是C/C++函式庫提供的,它的機制是很複雜的,例如為了分配一塊記憶體,庫函式會按照一定的演算法(具體的演算法可以參 考資料結構/作業系統)在堆記憶體中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由於記憶體碎片太多),就有可能呼叫系統功能去增加程式資料段 的記憶體空間,這樣就有機會分到足夠大小的記憶體,然後進行返回。顯然,堆的效率比棧要低得多。

明確區分堆與棧:
在bbs上,堆與棧的區分問題,似乎是一個永恆的話題,由此可見,初學者對此往往是混淆不清的,所以我決定拿他第一個開刀。
首先,我們舉一個例子:

相關推薦

C++ 應用程式 記憶體結構 --- BSS資料程式碼記憶體

二. 在C++中,記憶體分成5個區,他們分別是堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區1.棧,就 是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數、函式引數等。2.堆,就 是那些由new分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式去控制,一

將 Win32 C/C++ 應用程式遷移到 POWER 上的 Linux第 1 部分: 程序、執行緒共享記憶體服務 (轉載)

特別是程序、執行緒和共享記憶體服務)到 POWER 上 Linux 的對映。本文可以幫助您確定哪種對映服務最適合您的需要。作者向您詳細介紹了他在移植 Win32 C/C++ 應用程式時遇到的 API 對映。概述有很多方式可以將 Win32 C/C++ 應用程式移植和遷移到 p

記憶體池的設計實現 -- C++應用程式效能優化

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

記憶體池的設計實現 -- 《C++應用程式效能優化》

本書主要針對的是 C++ 程式的效能優化,深入介紹 C++ 程式效能優化的方法和例項。全書由 4 個篇組成,第 1 篇介紹 C++ 語言的物件模型,該篇是優化 C++ 程式的基礎;第 2 篇主要針對如何優化 C++ 程式的記憶體使用;第 3 篇介紹如何優化程式的啟動效能;第 4 篇介紹了三類效能優化工具,即

C# 應用程式執行時異常資訊捕獲

示例: static class Program { /// <summary> /// 應用程式的主入口點。 /// </summary> [STAThread] static void Main()

C#應用程式只允許執行一個例項多次執行的時候啟用當前例項顯示其介面

  很多時候,我們開發的程式,需要單例執行的的功能,即整個應用程式只允許同時執行最多一個例項,重複執行的時候,啟用當前實力,顯示其介面。   在C#程式中,其解決方案有多重,可以參照Charles Chen 的C#程式只允許執行一個例項的解決方案一文。   

C/C++應用程式記憶體洩漏檢查統計方案

  一、前緒   C/C++程式給某些程式設計師的幾大印象之一就是記憶體自己管理容易洩漏容易崩,筆者曾經在一個產品中使用C語言開發維護部分模組,只要產品有記憶體洩漏和崩潰的問題,就被甩鍋“我的程式是C#開發的記憶體都是託管的,C++那邊也沒有記憶體(庇護其好友),肯定是C這邊的問題”

C++應用程式中設定生成dump並使用VS進行除錯

首先,包含標頭檔案 #include "Windows.h" #include "DbgHelp.h" 其次,在程式碼中新增這兩個函式 int GenerateMiniDump(HANDLE hFile, PEXCEPTION_POINTERS pExceptionPointers, P

java C++ Socket程式傳送結構

       主要技術問題:windows,linux等系統採用LITTLE_ENDIAN位元組序,而java自身採用BIG_ENGIAN位元組序,BIG_ENGIAN是指低地址存放最高有效位元組(MSB),而LITTLE_ENDIAN則是

C++ 行內函數 摘自 C++ 應用程式效能優化

行內函數 在C++語言的設計中,行內函數的引入可以說完全是為了效能的考慮。因此在編寫對效能要求比較高的C++程式時,非常有必要仔細考量行內函數的使用。 所謂"內聯",即將被呼叫函式的函式體程式碼直接地整個插入到該函式被呼叫處,而不是通過call語句進行。當然,編譯器在真正進行"內聯"時,因為考慮到被行內函數

使用Boost::Python在C++應用程式中嵌入Python:第二部分

在第1部分中,我們瞭解瞭如何在C++應用程式中嵌入Python,包括從應用程式呼叫Python程式碼的幾種方法。雖然我之前承諾在第2部分中完整實現一個配置解析器,但我認為看一下錯誤解析會更有建設性。一旦我們有一個很好的方法來處理Python程式碼中的錯誤,我將在第3部分中

使用Boost::Python在C++應用程式中嵌入Python:第一部分

在本系列教程的簡介中,我說了將Python程式碼整合到Granola程式碼庫中的動機。簡而言之,它可以使我使用Python語言和標準庫的好處來完成在C++中通常很痛苦或笨拙的任務。當然,底線是我不必移植任何已有的C++程式碼。 今天,我們看一下使用boost::pyth

第一個Android的應用程式目錄結構詳說

http://www.linuxidc.com/Linux/2011-12/48964p2.htm: http://www.linuxidc.com/Linux/2011-12/48964.htm 結構圖: 從上往下一一介紹: 1、  src資料夾一看就是放原始碼的,自己

Linux C++應用程式退出時的事件響應

#define SIGHUP 1 /* hangup */    SIGHUP是Unix系統管理員很常用的一個訊號。許多後臺服務程序在接受到該訊號後將會重新讀取它們的配置檔案。然而,該訊號的實際功能是通知程序它的控制終端被斷開。預設行為是終止程序。 #define SIGI

C語言程式結構

1.一個程式由一個或多個原始檔組成 (1)預處理指令 . 如#include<stdio.h> , #define #include<stdio.h>指令就是將stdio.h標頭檔案的內容讀進來,放在#include指令行,取代了#

在mac上使用VS Code編寫C#應用程式

Visual Studio Code是微軟的跨平臺的VS開發工具,依賴於dot net core的跨平臺功能。 首先需要在mac上安裝dot net core 開發包(包含dot net core 執行時),dot net core mac 版 官方網站: https://

C++中的類所佔記憶體空間總結(其中有一關於成員函式處於程式碼的解釋) 2011-12-9 16:16

#include<iostream.h> class a {}; class b{}; class c:public a{ virtual void fun()=0; }; class d:public b,public c{}; int main() { cout<&

C# 應用程式自刪除

示例應用:ClearDir.exe 可用於清理其他檔案 和 自刪除 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text;

[AnyDAC][Phys][ODBC][Microsoft][ODBC 驅動管理器]在指定的DSN中,驅動程式應用程式體系結構

使用plsql的odbc匯入器的時候會出現該問題: 原因是我是64位的系統!!! 解決方法:1.執行C:\Windows\SysWOW64\odbcad32.exe,開啟後如下圖所示: 2.點選新增,選擇如下圖所示Microsoft Excel Driver(*.xls)

C#--應用程式版本號釋出配置

程式的版本號設定 主程式引入名稱空間 App.config配置檔案新增配置程式碼 “` 主程式初始化 新增— this.lblVer