中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C標準庫堆內存函數的示例分析

發布時間:2021-06-07 14:46:03 來源:億速云 閱讀:150 作者:小新 欄目:開發技術

這篇文章主要為大家展示了“C標準庫堆內存函數的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“C標準庫堆內存函數的示例分析”這篇文章吧。

概述

C標準庫堆內存函數有4個:malloc、free、calloc、realloc,其函數聲明放在了#include <stdlib.h>中,主要用來申請和釋放堆內存。

堆內存的申請和釋放(wiki,chs),需要發起系統調用,會帶來昂貴的上下文切換(用戶態切換到內核態),十分耗時。另外,這些過程可能是帶鎖的,難以并行化。

對于操作系統而言,內存管理的基本單位是頁(通常為4K),而不是需要4 Bytes時,就給你分配4 Bytes,釋放4 Bytes時,就給你釋放4 Bytes。

因此,為了提升效率,操作系統會調用系統api(windows上是VirtualAlloc、VirtualFree,其他平臺是mmap、munmap)來實現一個Ansi C內存分配器(工作在用戶態),供C標準庫堆內存函數來使用。

C標準庫堆內存函數的示例分析

不同操作系統Ansi C內存分配器實現方案有所不同

  • windows:MSVCRT.DLL中使用NT heap實現

  • linux:glibc中使用ptmalloc實現

  • Android:使用jemalloc實現

內存碎片與碎片整理

(1)內存碎片(fragmentation):即空閑內存不能被利用。分為外部碎片(在分配單元間的未使用的內存);內部碎片(在分配單元中未使用的內存)

C標準庫堆內存函數的示例分析

(2)內存碎片的罪魁禍首就是小塊內存的頻繁分配

(3)內存碎片無法避免,只能通過內存分配器算法來減少,例如:接近大小的內存就近分配,釋放時能合并就合并,從而減少碎片

(4)上面講的內存碎片指的是虛擬內存碎片,OS是不管的,OS只管物理內存。

(5)平時我們說的內存碎片整理(defragment)或內存緊縮(memory compaction),是指OS對物理內存進行的碎片整理,把分開小的物理內存頁移動在一起形成一個大的整塊。

OS整理完物理內存后,會用新的物理內存地址來更新虛擬內存與物理內存映射表,這些對于上層邏輯都是透明的。

虛擬內存是不能進行碎片整理的,主要原因是碎片整理會移動內存,上層邏輯的指針地址確還是指向老的地址,這會導致致命錯誤。

內存分配器的好壞標準

(1)分配和釋放的效率

(2)內存分配器的利用率。包括以下幾個方面:

① 內存對齊導致的不可使用的內存碎片(內部碎片)

② 內存碎片太嚴重,使得分配大塊內存時,找不到空閑塊,最后導致內存分配失敗(外部碎片)

③ 內存頁始終有被使用,導致分配器無法及時釋放該頁的內存占用,使得整個內存分配器的內存占用被撐得很大,縮不回去

void* malloc( size_t size )

形參size為要求分配的字節數。如果函數執行成功,malloc返回獲得內存空間的首地址;如果函數執行失敗,那么返回值為NULL。

由于 malloc函數值的類型為void型指針,因此,可以將其值類型轉換后賦給任意類型指針,這樣就可以通過操作該類型指針來操作從堆上獲得的內存空間。

需要注意的是,malloc函數分配得到的內存空間是未初始化的。可通過調用memset來將其初始化為全0。

int* p = (int *) malloc(sizeof(int)*100);
 
if (p == NULL)
{
    printf("Can't get memory!\n");
}
 
memset(p, 0, sizeof(int)*100);

void free( void* ptr )

從堆上獲得的內存,在程序結束之前,系統不會將其自動釋放,需要程序員來自己管理,防止出現內存泄露。

free(p);
p = NULL;

void* calloc( size_t num, size_t size )

calloc函數的功能與malloc函數的功能相似,都是從堆分配內存。

函數返回值為void*。如果執行成功,從堆上獲得size * num大小的堆內存,并返回該內存塊的首地址。如果執行失敗,函數返回NULL。

與malloc函數不同的是,calloc函數得到的內存塊會被初始化為全0。由于提供了2個參數,比較適合為數組申請空間,可以將size設置為數組元素的空間長度,將num設置為數組的容量。

int* p = (int *) calloc(100,  sizeof(int));
 
if (p == NULL)
{
    printf("Can't get memory!\n");
}

void *realloc( void *ptr, size_t new_size )

為ptr重新分配大小為size的一塊內存空間。下面是這個函數的工作流程:

① 如果ptr為NULL,則函數相當于malloc(new_size),試著分配一塊大小為new_size的內存,如果成功將地址返回,否則返回NULL。

② 如果ptr不為NULL,查看ptr是不是在堆中,如果不是的話會拋出realloc invalid pointer異常。如果ptr在堆中,則查看new_size大小。

(a)如果new_size大小為0,則相當于free(ptr),將ptr指向的內存空間釋放掉,返回NULL。

(b)如果new_size小于原大小,只有new_size大小的數據會保存,后面地址的數據可能會丟失;

(c)如果new_size等于原大小,什么都沒有做;

(d)如果new_size大于原大小,則查看ptr指向的位置還有沒有足夠的連續內存空間,如果有的話,分配更多的空間,返回的地址和ptr相同;

如果沒有的話,在更大的空間內查找,如果找到new_size大小的空間,將舊的內容拷貝到新的內存中,把舊的內存釋放掉,則返回新地址,否則返回NULL。

int* p = (int*)malloc(sizeof(int));
*p = 3;
printf("p=%p\n", p);  // p=0000020B2966E310
printf("*p=%d\n", *p); // *p=3

p = (int*)realloc(p, sizeof(int));  // 什么也不做
printf("p=%p\n", p);  // p=0000020B2966E310
printf("*p=%d\n", *p); // *p=3

p = (int*)realloc(p, 1024 * sizeof(int)); // 創建4KB的內存塊  注:4KB為一個頁面的大小
printf("p=%p\n", p); // p=0000020B29673A50  注:由于不能在原來地址上擴容,會將原來地址內存釋放,并在新地址申請內存塊
printf("*p=%d\n", *p); // *p=3

realloc(p, 0);  // 相當于free(p)
p = NULL;

以上是“C標準庫堆內存函數的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c
AI

保康县| 邮箱| 峡江县| 怀柔区| 灯塔市| 万荣县| 阜新| 郴州市| 长宁县| 龙江县| 潞城市| 镇雄县| 桂东县| 久治县| 九江市| 高雄市| 阳谷县| 亚东县| 乌兰县| 休宁县| 昌宁县| 陕西省| 延长县| 云龙县| 武隆县| 富顺县| 柘荣县| 富锦市| 图片| 酉阳| 美姑县| 蒙自县| 左云县| 阳山县| 平泉县| 甘孜县| 公主岭市| 定州市| 吉木乃县| 诸城市| 巴里|