内存分配
我們已經知道,每一個進程內存包含多個段,如文本段、已初始化數據段、未初始化數據段和堆棧段等。程序中已初始化的全局變量和靜態變量會在已初始化數據段中,而未初始化的數據在未初始化數據段中。對于這些數據,程序運行的時候才分配內存,這里的分配內存,是由系統程序完成的。
系統程序需要為動態數據結構(例如鏈表和二叉樹等)分配額外的內存,這類的數據結構的大小由運行時所獲取的信息決定。內存分配可以在堆或堆棧上進行。
下圖是進程內存布局圖:
1、在堆上分配內存
圖中,堆是一段長度可變的連續虛擬內存,開始于未初始化數據段的末尾,隨著內存的分配和釋放而增減。可以通過改變堆的大小來實現內存的分配。通常將堆的當前內存邊界稱為“program break”。
C語言中可以使用malloc()實現內存分配,malloc是基于brk()和sbrk()系統調用實現的。brk和sbrk可以調整program break,由于program break就是未使用內存和堆之間的界限,因此修改program break就是改變堆的大小。最開始的時候,program break在未初始化數據段的末尾,和&end位置相同。
需要注意的是,分配的內存是虛擬內存,并沒有分配實際物理內存,內核會在進程首次訪問這些虛擬內存時自動分配新的物理內存分頁。下面是brk和sbrk系統調用的具體格式:
#include <unistd.h> int brk(void *end_data_segment);//Returns 0 on success,or -1 on error void *sbrk(intptr_t increment);//Returns previous program break on success,or (void *)-1 on errorbrk將program break設置為參數end_data_segment,注意,虛擬內存以頁為單位進行分配,end_data_segment會和下一個內存頁的邊界處對齊。同時還要注意,當試圖將program break設置為比當前值小的位置時,可能會發生意想不到的錯誤。
sbrk系統調用將program break增加參數increment大小。intptr_t是正數數據類型。如果調用成功,sbrk返回前一個program break的地址。也就是說,如果增加program break,那么sbrk將返回新分配的內存的起始位置的指針。
小技巧:可以調用sbrk(0)得到當前program break的位置。
C語言中的內存分配函數malloc和內存釋放函數free是基于brk和sbrk系統調用實現的。下面是具體格式:
#include <stdlib.h> void *malloc(size_t size);//Returns pointer to allocated memory on success,or NULL on error void free(void *ptr);malloc函數返回新分配內存的起始位置的指針,如果無法分配內存,則返回NULL;free函數釋放參數ptr指向的內存塊。由于以下的原因,free函數通常不降低program break的位置:
- 被釋放的內存塊通常會位于堆的中間,而非堆的頂部;
- 這樣減少了sbrk系統調用次數;
- 在大多數情況下,降低program break的位置不會對那些分配大量內存的程序有多少幫助,因為它們通常傾向于持有已分配內存或是反復釋放和重新分配內存,而非釋放所有內存后再持續運行一段時間。
下面給出幾個運行示例:
(1)分配1000個內存塊,每個10240字節,步長是1,全部釋放 可以看到,當釋放的內存足夠大的時候,free會降低program break; (2)連續釋放前999個內存塊 結果program break沒有變化,因為釋放的內存塊在堆的中間; (3)每隔一個內存塊釋放一個 program break也沒有變化 (4)釋放后500塊內存塊 program break下降了,free使用sbrk系統調用實現。 free函數會在釋放是將相鄰的內存塊合并為一個連續的內存塊。 2、在堆棧上分配內存 alloca函數通過增加棧幀的大小來分配內存。格式如下:
#include <alloca.h> void *alloca(size_t size);//Returns pointer to allocated block of memoryalloca函數有幾個優點,一個就是速度快,因為編譯器將它作為內聯代碼處理。還有,alloca分配的內存會隨棧幀的移除而自動釋放,即當調用alloca的函數返回時。這是因為函數返回時所執行的代碼會重置棧指針寄存器,使其指向前一幀的末尾。
總結
- 上一篇: 文件描述符与打开文件的关系
- 下一篇: UNIX网络编程笔记(1):TCP简介