Linux 應用開發之內存分配

來源 | TLPI 系統編程筆記

整理 & 排版 | 嵌入式應用研究院

1、在堆上分配內存

堆是長度可變的連續虛擬內存,始於進程未初始化數據段的末尾,將堆當前的內存邊界稱爲 "program break"。

1.1、調整 program break

改變堆的大小,其實就像命令內核改變進程的 program break 位置一樣,最初,program break 的位置正好位於未初始化數據段末尾之後。

#include <unistd.h>

int brk(void *end_data_segment);

void *sbrk(intptr_t increment);

在 program break 的位置提升之後,程序可以訪問新分配區域內的任何內存地址,而此時物理內存頁尚未分配,內核會在進程首次視圖訪問這些虛擬內存地址時自動分配新的物理內存頁。

1.2、在堆上分配內存
#include <stdlib.h>

void *malloc(size_t size);
#include <stdlib.h>

void free(void *ptr);
1.3、調用 free() 還是不調用 free()

進程終止時,其佔用的所有內存都會返還給操作系統,這包括在堆內存中由 malloc() 函數包內一系列函數所分配的內存。

雖然依靠終止進程來自動釋放內存對大多數程序來說是可接受的,但是基於以下原因,最好能夠在程序中顯式釋放所有分配的內存:

1.4、malloc() 和 free() 的實現

malloc() 的實現很簡單:

malloc() 分配內存時會多分配幾個字節用來記錄這塊內存的大小整數值,這個整數位於內存塊的起始處,而實際返回給調用者的內存地址恰好位於這一長度記錄字節之後。

free() 的實現更爲有趣:

當將內存塊置於空閒內存列表 (雙向鏈表) 時,free() 會使用內存塊本身的空間來存放鏈表指針,將自身添加到列表中:

隨着對內存不斷地釋放和重新分配,空閒列表中的空閒內存會和已經分配的在用內存混雜在一起:

避免內存分配相關問題,應該遵循的準則:

1.5、malloc 調試的工具和庫

glibc 提供的 malloc 調試工具:

1.6、控制和監控 malloc 函數包

glibc 手冊介紹了一系列非標準函數,可以用於監測和控制 malloc 包中的函數:

堆上分配內存的其他方法
用 calloc() 和 realloc() 分配內存
#include <stdlib.h>

void *calloc(size_t numitems, size_t size);
#include <stdlib.h>

void *realloc(void *ptr, size_t size);
1.7、分配對齊的內存
#include <malloc.h>

void *memalign(size_t boundary, size_t size);
#include <stdlib.h>

int posix_memalign(void **memptr, size_t alignment, size_t size);

2、在堆棧上分配內存

#include <alloca.h>

void *alloca(size_t size);
func(x,alloca(size),z) //@ 錯誤的示範
  
//@ 必須按下面的方式進行
void* y;
y = alloca(size);
func(x,y,z);
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ikVEzOIC9pUQNdUOXXqqnw