最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解C標(biāo)準(zhǔn)庫堆內(nèi)存函數(shù)

 更新時(shí)間:2021年06月07日 10:10:14   作者:可可西  
在C/C++語言中,我們知道內(nèi)存分為這幾種:程序全局變量內(nèi)存、棧內(nèi)存、堆內(nèi)存。其中堆內(nèi)存就是通過malloc(new)來分配的內(nèi)存,本文我們來探討一下C標(biāo)準(zhǔn)庫堆內(nèi)存函數(shù)。

概述

C標(biāo)準(zhǔn)庫堆內(nèi)存函數(shù)有4個(gè):malloc、free、calloc、realloc,其函數(shù)聲明放在了#include <stdlib.h>中,主要用來申請(qǐng)和釋放堆內(nèi)存。

堆內(nèi)存的申請(qǐng)和釋放(wiki,chs),需要發(fā)起系統(tǒng)調(diào)用,會(huì)帶來昂貴的上下文切換(用戶態(tài)切換到內(nèi)核態(tài)),十分耗時(shí)。另外,這些過程可能是帶鎖的,難以并行化。

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

因此,為了提升效率,操作系統(tǒng)會(huì)調(diào)用系統(tǒng)api(windows上是VirtualAlloc、VirtualFree,其他平臺(tái)是mmap、munmap)來實(shí)現(xiàn)一個(gè)Ansi C內(nèi)存分配器(工作在用戶態(tài)),供C標(biāo)準(zhǔn)庫堆內(nèi)存函數(shù)來使用。

不同操作系統(tǒng)Ansi C內(nèi)存分配器實(shí)現(xiàn)方案有所不同

  • windows:MSVCRT.DLL中使用NT heap實(shí)現(xiàn)
  • linux:glibc中使用ptmalloc實(shí)現(xiàn)
  • Android:使用jemalloc實(shí)現(xiàn)

內(nèi)存碎片與碎片整理

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

(2)內(nèi)存碎片的罪魁禍?zhǔn)拙褪切K內(nèi)存的頻繁分配

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

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

(5)平時(shí)我們說的內(nèi)存碎片整理(defragment)或內(nèi)存緊縮(memory compaction),是指OS對(duì)物理內(nèi)存進(jìn)行的碎片整理,把分開小的物理內(nèi)存頁移動(dòng)在一起形成一個(gè)大的整塊。

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

虛擬內(nèi)存是不能進(jìn)行碎片整理的,主要原因是碎片整理會(huì)移動(dòng)內(nèi)存,上層邏輯的指針地址確還是指向老的地址,這會(huì)導(dǎo)致致命錯(cuò)誤。

內(nèi)存分配器的好壞標(biāo)準(zhǔn)

(1)分配和釋放的效率

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

① 內(nèi)存對(duì)齊導(dǎo)致的不可使用的內(nèi)存碎片(內(nèi)部碎片)

② 內(nèi)存碎片太嚴(yán)重,使得分配大塊內(nèi)存時(shí),找不到空閑塊,最后導(dǎo)致內(nèi)存分配失?。ㄍ獠克槠?/p>

③ 內(nèi)存頁始終有被使用,導(dǎo)致分配器無法及時(shí)釋放該頁的內(nèi)存占用,使得整個(gè)內(nèi)存分配器的內(nèi)存占用被撐得很大,縮不回去

void* malloc( size_t size )

形參size為要求分配的字節(jié)數(shù)。如果函數(shù)執(zhí)行成功,malloc返回獲得內(nèi)存空間的首地址;如果函數(shù)執(zhí)行失敗,那么返回值為NULL。

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

需要注意的是,malloc函數(shù)分配得到的內(nèi)存空間是未初始化的??赏ㄟ^調(diào)用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 )

從堆上獲得的內(nèi)存,在程序結(jié)束之前,系統(tǒng)不會(huì)將其自動(dòng)釋放,需要程序員來自己管理,防止出現(xiàn)內(nèi)存泄露。

free(p);
p = NULL;

void* calloc( size_t num, size_t size )

calloc函數(shù)的功能與malloc函數(shù)的功能相似,都是從堆分配內(nèi)存。

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

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

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的一塊內(nèi)存空間。下面是這個(gè)函數(shù)的工作流程:

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

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

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

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

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

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

如果沒有的話,在更大的空間內(nèi)查找,如果找到new_size大小的空間,將舊的內(nèi)容拷貝到新的內(nèi)存中,把舊的內(nèi)存釋放掉,則返回新地址,否則返回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)); // 創(chuàng)建4KB的內(nèi)存塊  注:4KB為一個(gè)頁面的大小
printf("p=%p\n", p); // p=0000020B29673A50  注:由于不能在原來地址上擴(kuò)容,會(huì)將原來地址內(nèi)存釋放,并在新地址申請(qǐng)內(nèi)存塊
printf("*p=%d\n", *p); // *p=3

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

以上就是詳解C標(biāo)準(zhǔn)庫堆內(nèi)存函數(shù)的詳細(xì)內(nèi)容,更多關(guān)于C標(biāo)準(zhǔn)庫堆內(nèi)存函數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語言簡明介紹常見關(guān)鍵字的用法

    C語言簡明介紹常見關(guān)鍵字的用法

    關(guān)鍵字是C語言非常重要的一部分,熟練的掌握和使用關(guān)鍵字有助于我們更加熟悉了解C語言,同時(shí)C語言的關(guān)鍵字也是面試筆試中常考的內(nèi)容。C語言的關(guān)鍵字共有32個(gè),但并不是每個(gè)關(guān)鍵字都有坑,本篇文章將通過理論聯(lián)系實(shí)際的方式為大家講解C語言中易混易錯(cuò)以及??嫉囊恍╆P(guān)鍵字
    2022-06-06
  • C++基于prim實(shí)現(xiàn)迷宮生成

    C++基于prim實(shí)現(xiàn)迷宮生成

    這篇文章主要為大家詳細(xì)介紹了C++基于prim實(shí)現(xiàn)迷宮生成,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • C語言中字符串常用操作總結(jié)

    C語言中字符串常用操作總結(jié)

    C語言是一種非常流行的編程語言,它支持各種數(shù)據(jù)類型,包括整數(shù)、浮點(diǎn)數(shù)、字符和字符串等,本文將介紹?C語言中字符串的相關(guān)知識(shí),包括字符串的定義、初始化、賦值等,需要的可以參考一下
    2023-05-05
  • C語言中的回調(diào)函數(shù)實(shí)例

    C語言中的回調(diào)函數(shù)實(shí)例

    如果函數(shù)A的指針作為函數(shù)B的參數(shù),在函數(shù)B中利用該指針調(diào)用函數(shù)A,則此時(shí)的A就是回調(diào)函數(shù)。
    2014-04-04
  • C語言命令行參數(shù)的使用詳解

    C語言命令行參數(shù)的使用詳解

    本文主要介紹了C語言命令行參數(shù)的使用詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • OpenCV圖像旋轉(zhuǎn)Rotate的詳細(xì)介紹

    OpenCV圖像旋轉(zhuǎn)Rotate的詳細(xì)介紹

    這篇文章主要介紹了OpenCV圖像旋轉(zhuǎn)Rotate,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • C語言實(shí)現(xiàn)頁面置換算法

    C語言實(shí)現(xiàn)頁面置換算法

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)頁面置換算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • C++基礎(chǔ)學(xué)習(xí)之函數(shù)重載的簡單介紹

    C++基礎(chǔ)學(xué)習(xí)之函數(shù)重載的簡單介紹

    函數(shù)重載是一種特殊情況,C++允許在同一作用域中聲明幾個(gè)類似的同名函數(shù),這些同名函數(shù)的形參列表(參數(shù)個(gè)數(shù),類型,順序)必須不同,常用來處理實(shí)現(xiàn)功能類似數(shù)據(jù)類型不同的問題。這篇文章主要給大家介紹了關(guān)于C++基礎(chǔ)學(xué)習(xí)之函數(shù)重載的相關(guān)資料,需要的朋友可以參考下
    2019-01-01
  • C語言數(shù)據(jù)結(jié)構(gòu)之堆排序的優(yōu)化算法

    C語言數(shù)據(jù)結(jié)構(gòu)之堆排序的優(yōu)化算法

    堆排序Heap?Sort就是利用堆進(jìn)行排序的方法,下面這篇文章主要給大家介紹了關(guān)于C語言數(shù)據(jù)結(jié)構(gòu)之堆排序的優(yōu)化算法的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • C語言計(jì)算分段函數(shù)問題

    C語言計(jì)算分段函數(shù)問題

    這篇文章主要介紹了C語言計(jì)算分段函數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評(píng)論

天峨县| 禹州市| 英德市| 安徽省| 清原| 南岸区| 蕲春县| 循化| 涿鹿县| 子洲县| 勃利县| 南川市| 马边| 永春县| 通州市| 米林县| 咸阳市| 库伦旗| 桃园县| 普洱| 深水埗区| 临猗县| 锡林浩特市| 榕江县| 河曲县| 新津县| 登封市| 临海市| 阿瓦提县| 星子县| 安化县| 林芝县| 鹤峰县| 喀喇沁旗| 凤庆县| 龙南县| 邯郸市| 鄱阳县| 高台县| 姜堰市| 广州市|