日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

内存分配

發布時間:2023/11/30 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内存分配 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我們已經知道,每一個進程內存包含多個段,如文本段、已初始化數據段、未初始化數據段和堆棧段等。程序中已初始化的全局變量和靜態變量會在已初始化數據段中,而未初始化的數據在未初始化數據段中。對于這些數據,程序運行的時候才分配內存,這里的分配內存,是由系統程序完成的。

系統程序需要為動態數據結構(例如鏈表和二叉樹等)分配額外的內存,這類的數據結構的大小由運行時所獲取的信息決定。內存分配可以在堆或堆棧上進行。

下圖是進程內存布局圖:



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 error

brk將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的位置不會對那些分配大量內存的程序有多少幫助,因為它們通常傾向于持有已分配內存或是反復釋放和重新分配內存,而非釋放所有內存后再持續運行一段時間。
下面的程序說明了free對program break的影響。程序有多個參數,第一個參數是分配內存的塊數,第二個參數是每個內存塊的大小,第三個參數指定了釋放內存塊的步長,第四個和第五個參數限定了釋放內存塊的范圍,如果不指定,就當全部范圍。 #include <unistd.h> #include <stdlib.h> #include "error_functions.c" #include "get_num.c" #define MAX_ALLOCS 1000000 int main(int argc,char *argv[]) {if(argc<3||strcmp(argv[1],"--help")==0)usageErr("%s num_blocks block_size [step [min [max]]]\n",argv[0]);char *ptr[MAX_ALLOCS];int freeStep,freeMin,freeMax,blockSize,blockNum;blockNum=getInt(argv[1],GN_GT_0,"block_num");if(blockNum>MAX_ALLOCS)errExit("block_num>MAX_ALLOCS\n");blockSize=getInt(argv[2],GN_GT_0|GN_ANY_BASE,"block_size");freeStep=(argc>3)?getInt(argv[3],GN_GT_0,"step"):1;freeMin=(argc>4)?getInt(argv[4],GN_GT_0,"min"):1;freeMax=(argc>5)?getInt(argv[5],GN_GT_0,"max"):blockNum;if(freeMax>blockNum)errExit("bigger");printf("Initial program break: %10p\n",sbrk(0));int j=0;for(j=0;j<blockNum;j++){if((ptr[j]=malloc(blockSize))==NULL)errExit("malloc");}printf("Program break is now: %10p\n",sbrk(0));for(j=freeMin-1;j<freeMax;j+=freeStep)free(ptr[j]);printf("After free(),program break is:%10p\n",sbrk(0));exit(EXIT_SUCCESS); }
下面給出幾個運行示例:

(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的函數返回時。這是因為函數返回時所執行的代碼會重置棧指針寄存器,使其指向前一幀的末尾。

總結

以上是生活随笔為你收集整理的内存分配的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。