iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
自我挑戰組

當你凝視linux, linux也在凝視你系列 第 16

Day16 熟悉又陌生的 malloc()

  • 分享至 

  • xImage
  •  

前言

昨天看過了如何對VMA 進行操作,今天要來研究兩個熟悉又陌生的函數, malloc()mmap()

malloc()

malloc() 是C語言中的虛擬記憶體分配函數,以下舉兩個例子進行比較,讓大家更貼近 malloc()

流程圖如下

以上是 malloc() 大致的呼叫順序, malloc() 函數用在為 user space 空間分配行程定址空間,也就是分配一塊VMA。 用簡單的比喻來說 malloc() 就是先分給使用者一個空箱子,直到要真正使用箱子的時候才在裡面裝東西。
以下舉出兩個例子

void testA(void){
    char* bufA = malloc();
    ...
    *bufA = 100;
    ...
}

void testB(void){
    char* bufB = malloc(100);
    mlock(bufB, 100);
    ...
}

分別用兩個行程A,B執行 testA()testB() ,兩個例子同樣使用了 malloc() 但是 testA() 先給一個虛擬位址,直到第四行實際要放入資料的時候,才會真正在實體記憶體找出一個位子。 testB() 則是利用 mlock 函數直接找到映射的實體記憶體了。以下來自man7

mlock(), mlock2(), and mlockall() lock part or all of the calling process's virtual address space into RAM, preventing that memory from being paged to the swap area.

testA() 在真正需要實體記憶體時,CPU會查詢分頁表,發現該虛擬位址映射的分頁表為空,進而引發缺頁異常(page fault),在缺頁異常的處理中一頁一頁的分配實體記憶體。

若使用 printf() 對這兩個行程輸出 malloc() 分配的虛擬位址,會發現兩個行程印出的結果相同,那麼這兩個相同的虛擬位址是否會引發衝突呢?
答案是否定的,每個行程都有屬於自己的分頁表, 這個分頁表放在 mm_struct 資料結構中的 pgd 裡,pgd 會指向每個行程專屬的分頁表的起始位置。 在每個行程初始化的時候會建立專屬的 mm_struct ,其中會包含屬於該行程的分頁表、管理VMA的紅黑樹、鏈表,所以每個行程管理自己的VMA都有自己的資料結構,因此不會因為虛擬位址相同而有所衝突。

以下是幾個常見的記憶體分配的函數

void* malloc(size_t num); 

void* calloc(size_t num, size_t size);

malloc() 就如同上面講的,先 num 大小的虛擬記憶體,但是不分配實際的記憶體,直到要使用的時候才實際分配實體記憶體。 calloc() 使用了兩個參數, num 是總共要分配的記憶體大小, size 則是每個區塊的大小是多少,並且立即分配實體記憶體並且將所有區塊初始值設為0。 以下是簡單使用兩個函數的例子

// C program to demonstrate the use of calloc()
// and malloc()
#include <stdio.h>
#include <stdlib.h>

int main()
{
	int* arr;

	// malloc() 分配大小是五個 int大小的虛擬記憶體
	// containing garbage values
	arr = (int*)malloc(5 * sizeof(int)); // 5*4bytes = 20 bytes
	// 砍掉上面分配的空間
	free(arr);

	// calloc() 分配五個int大小的空間並且初始化為0
	arr = (int*)calloc(5, sizeof(int));
	//砍掉上述的空間
	free(arr);
	return (0);
}

剛好想到另外兩個長得很像的函數, vmalloc()kmalloc

void *vmalloc(unsigned long size)

void *kmalloc(size_t size, int flags);

vmalloc()size 代表要分配的大小, kmalloc()size 要分配的大小, flags 代表這段記憶體的標記是什麼。
這兩個函數的只有微小的差異, kmalloc() 會分配連續的虛擬記憶體,同時也會分配連續的實體記憶體。kmalloc()vmalloc() 的差別在於後者分配的實體記憶體空間不是連續的。在普通的使用狀態下,這兩者並沒有明顯的差別, 在 Kernel 內kmallocvmalloc 常用的理由是因為效能問題, 當實體記憶體需要被 DMA 裝置存取的時候,效能差異就會出現了, 因為使用 vmalloc() 需要進行映射,會讓效能比較低, 不過 vmalloc() 可以分配比較大的空間。

kmalloc and vmalloc


上一篇
Day15 對 VMA 上下其手
下一篇
Day17 探訪 mmap( )
系列文
當你凝視linux, linux也在凝視你30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言