C 記憶體分割槽

2022-09-15 03:06:12 字數 3649 閱讀 4500

系統執行時不能所有資料都讀取到cpu暫存器,所以需要有快取,快取不夠用了所以有多級快取。快取的儲存器畢竟還是相對昂貴的,所以還有記憶體(也叫外存)。但是資料在記憶體中的是怎樣存放,這又是乙個問題。

首先從位元組層面看:資訊在計算機肯定是0/1的bit位元位形式儲存,習慣是8bit作為乙個位元組作為乙個有意義的儲存單位,但是有些資料的最小儲存單位是多個位元組,例如:int型別。多位元組的資料在記憶體或者暫存器儲存方式可以分為:大端、小端。

整體記憶體層面看:記憶體中有執行的二進位制**程式、有**執行時需要不斷改變的變數、有**執行呼叫但是不需要改變的常量、還有需要的資料等等。記憶體中的資料可以看做多小電容,不停讀寫修改會讓這些電容充放電,充放電頻繁會產生磁場對附近的其他資料影響。為了抵消這些影響,系統把記憶體分為多個區,這樣可以有效提公升資料的安全性。企業級伺服器使用的一般都是帶ecc(error correcting code)錯誤檢查糾正技術的記憶體

程式在記憶體中主要分幾個區域,每個區域儲存那些資料(此處把程式、變數等都看做資料),主要有以下幾種說法:

第一種說法是:5個區域(堆區、棧區、全域性/靜態儲存區、常量儲存區、自由儲存區)。

第二種說法是:5個區域(堆區、棧區、全域性/靜態區、(字元)常量儲存區、程式**區)。

第三種說法是:5個區域(bss是英文block started by symbol的簡稱、text段是程式**段、data包含靜態初始化的資料、stack儲存函式的區域性變數和引數、heap儲存函式內部動態分配記憶體)

第四種說法是:4個區域(堆區、棧區、全域性/靜態儲存區、常量區)。

堆區

棧區

全域性

/靜態儲存區

堆是「先進先出」

(first in first out

,fifo)

資料結構。

一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由作業系統

(os)

**。注意

它與資料結構中的堆是兩回事,分配方式倒是類似於鍊錶。

它只允許在堆的一端插入資料,在另一端移走資料。堆的位址空間「向上增加」,即當堆上儲存的資料越多,堆的位址就越高。

有的說法是:程式設計師分配通過malloc申請的動態記憶體在堆區建立,free來結束並釋放;new建立的物件在自由儲存區建立。new申請的記憶體需要程式設計師delete,malloc申請的記憶體需要free釋放,從而防止記憶體洩漏。對於堆來說,釋放工作由程式設計師控制,容易產生memory leak

棧是一種「後進先出」

(last in first out

,lifo)

的資料結構。

由編譯器在需要的時候分配,在不需要的時候自動清除。

存放函式的引數值,區域性變數的值等

棧另外乙個重要的特徵是,它的地 址空間「向下減少」,即當棧上儲存的資料越多,棧的位址就越低。棧(

stack

)的頂部在可讀寫的

ram區的最後。

全域性變數和靜態變數被分配此區域

(在以前的

c語言中,全域性變數又分為初始化的和未初始化的,在

c++裡面沒有這個區分了,他們共同占用同一塊記憶體區)。

段的起始位置也是由連線定位檔案所確定。

大小在編譯連線時自動分配,它和程式大小沒有關係,但和程式使用到的全域性變數,常量數量相關。

注意:堆區資料有先進先出特性,棧區資料有後進先出特性,但是並不是說只能依次取資料。具體怎麼取堆/棧區中間資料需要看堆/棧是怎麼實現的。如果棧是用常見的最大/最小樹結構實現,那麼就是取中間資料後再對其進行排序即可。

主要討論點是:自由儲存區(free store),堆區有什麼區別

堆區和棧區主要區別集中在以下幾點:

管理方式不同。

空間大小不同。

能否產生碎片不同。

生長方向不同。

分配方式不同。

分配效率不同。

堆區

棧區

堆區的使用由程式設計師通過new/malloc申請,需要由程式設計師顯式的delete/free釋放,如果沒有顯式是放程式結束系統會自動**,但是程式執行時由記憶體洩漏的風險。

一般來講在32位系統下,堆記憶體可以達到4g的空間,從這個角度來看堆記憶體幾乎是沒有什麼限制的。

對於堆來講,頻繁的new/delete勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。

對於堆來講,生長方向是向上的,也就是向著記憶體位址增加的方向。

堆都是動態分配的,沒有靜態分配的堆。

堆則是c/c++函式庫提供的,它的機制是很複雜的,例如為了分配一塊記憶體,庫函式會按照一定的演算法(具體的演算法可以參考資料結構/作業系統)在堆記憶體中搜尋可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由於記憶體碎片太多),就有可能呼叫系統功能去增加程式資料段的記憶體空間,這樣就有機會分到足夠大小的記憶體,然後進行返回。顯然,堆的效率比棧要低得多。

由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數、函式引數。

對於棧來講,一般都是有一定的空間大小的,例如,在vc6下面,預設的棧空間大小是xm,x往往是固定的。比較小。

對於棧來講,則不會存在這個問題,因為棧是先進後出的佇列,他們是如此的一一對應,以至於永遠都不可能有乙個記憶體塊從棧中間彈出,在他彈出之前,在他上面的後進的棧內容已經被彈出

對於棧來講,它的生長方向是向下的,是向著記憶體位址減小的方向增長。

棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配由alloca函式進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。

以上的記憶體分割槽中的堆疊並不對應資料結構中的堆/棧。

堆(heap)是電腦科學中一類特殊的資料結構的統稱。堆通常是乙個可以被看做一棵完全二叉樹的陣列物件。

堆分為兩種:最大堆和最小堆,兩者的差別在於節點的排序方式。

棧(stack)限定僅在表尾進行插入和刪除操作的線性表。這一端被稱為棧頂,相對地,把另一端稱為棧底。向乙個棧插入新元素又稱作進棧、入棧或壓棧。

原來的意思,如此才能把握本質。棧,儲存貨物或供旅客住宿的地方,可引申為倉庫、中轉站,所以引入到計算機領域裡,就是指資料暫時儲存的地方,所以才有進棧、出棧的說法。

的特點後進先出的原則儲存資料,先進入的資料被壓入棧底,最後的資料在棧頂,需要讀資料的時候從棧頂開始彈出資料(最後乙個資料被第乙個讀出來)。棧具有記憶作用,對棧的插入與刪除操作中,不需要改變棧底指標。

對記憶體分割槽有一些了解,知道為什麼記憶體中資料要分開存,然後了解大概可以分幾個區即可。具體分幾個,new的物件儲存在**,malloc申請的內存在**這些細節需要看具體的編譯器和作業系統。如果不是做編譯器的,可以對這些有了解即可。

非常感謝以下的部落格文章:

c 記憶體分割槽

堆 由程式設計師手動分配和釋放,完全不同於資料結構中的堆,分配方式類似鍊錶。由malloc c語言 或new c 來分配,free c語言 和delete c 釋放。若程式設計師不釋放,程式結束時由系統釋放。棧 由編譯器自動分配和釋放的,存放函式的引數值 區域性變數的值等。操作方式類似資料結構的棧。...

C 記憶體分割槽

前言 最近正在學習有關static的知識,發覺對c 的記憶體分割槽不是很了解,上網查了很多資料,遂將這幾天的學習筆記進行了簡單整理,發表在這裡 棧區 stack 主要用來存放函式的引數以及區域性變數。棧區由系統進行記憶體管理,在函式完成執行時,系統會自行釋放棧區的記憶體,而不需要使用者參與管理。整個...

C 記憶體分割槽

程式編譯後生成的二進位制檔案放在記憶體中的 區 全域性變數 函式外宣告的變數 靜態區域性變數 static修飾的變數 常量字串常量 hello world const 全域性變數 全域性常量 note const修飾的區域性變數不在全域性區 且區域性變數也不在全域性區 區域性變數 函式引數 存放在棧...