一, 內存結構描述
1. 查看進程
-
getpid()
這個函數是Linux系統(tǒng)庫函數, 在使用時需要導入頭文件 #include <unistd.h> , 這個函數用來獲取當前進程的進程id號, 或者通過ps aue
也可以查看當前系統(tǒng)下運行的所有進程, 然后找到當前程序的進程號. -
/proc/${pid}/
這個文件夾的生命周期是程序運行過程中, 程序結束時文件夾銷毀. 該文件夾下存放對當前程序運行過程中內存分配的描述文件.
2. 內存分配
- 所有程序的起始地址都是0x08048000, 內存分配依次是 代碼區(qū), 全局區(qū), 堆區(qū), 棧區(qū)
- 關于堆區(qū)內存分配方式: malloc, new, sbrk, brk
- malloc 與 new
malloc 使用一個鏈表的數據結構維護和分配空間.對malloc分配的空間不要越界訪問.因為容易破壞后臺維護結構.導致malloc/free/calloc/realloc不正常工作.
{
分配的空間;
上一個空間的信息;
下一個空間的信息;
當前空間大小等信息;
}
3.new 與 malloc
- new 是通過malloc 實現的. new在申請到空間后, 還會執(zhí)行空間的初始化. 對于基本類型數據, 直接初始化為默認值. 對于用戶自定義類型, 需要調用指定的構造器. 同樣地, 在釋放空間時, delete 是通過調用free 實現, delete 是先調用析構器, 再調用free釋放空間.
- new 只調用一次構造器. 而 new [ ] 會循環(huán)對每個區(qū)域調用構造器.
-
Stu *p = new Stu[30];
對于自定義類型 p 的釋放. delete 和 delete [ ]; 都能釋放掉這塊空間. delete 只會調一次析構, 而 delete[ ] 會對p 所指向的30 個對象空間依次調用析構.
4.函數調用棧空間的分配與釋放
- 函數執(zhí)行的時候有自己的臨時楒暄剩空間, 函數的參數就在臨時棧中.
二, 虛擬內存
每個應用程序在啟動時, 并沒有直接訪問內存的物理地址. 而是通過虛擬內存映射的方式向物理內存申請存儲空間. 對于Linux 系統(tǒng)而言, 每個程序的起始的虛擬地址都是 0x80084000.
1. 虛擬內存映射
應用程序在運行的過程中所使用的地址并不是物理地址, 而是邏輯地址(虛擬內存). 對于邏輯地址, 不過是一個整形數據而已. 如果對int型分配的是4個字節(jié). 那么32位的尋址方位剛好是4G, 十六進制表示0x1000. 我們將這個數值成為一個頁.
2. 虛擬內存分配
從上面的內存分配結構圖中, 我們可以看到, 系統(tǒng)分配內存都是 1 個頁 或 1個頁的整數倍. 每個程序在運行的時候, 都會在物理內存上有自己的映射. 一旦訪問沒有映射的物理內存區(qū)域, 程序就會出現崩潰.
3. brk 和sbrk
void* sbrk(int size)
sbrk 可以用來分配空間, sbrk(0) 第一次運行時, 我們通常用來獲取沒有映射的空閑空間的首地址. 與malloc 不同, malloc維護的是一個結構體, 而sbrk維護的是一個整形的指針.
int brk(void* end)
brk用來分配空間和釋放空間.
sbrk 操作的是絕對位置, brk操作的是相對位置.
sbrk 常用來獲取地址, brk常用來分配空間. 兩者搭配使用.