malloc中的系統調用brk和mmap


malloc中的系統調用brk和mmap

環境
  • ubuntu14.04

  • malloc通過系統調用的方式從操作系統申請內存,malloc內部又通過系統調用brk()mmap來申請內存的。入下圖進程虛擬內存布局所示,mmap對應Memory Mapping Segment,brk對應Heap.

brk

  • brk通過增加program break的位置(brk)從內核申請(非零值初始化)內存。一開始堆段(heap segment)的其實位置(start_brk)和結束位置(brk)指向同一個位置。

    • 當ASLR(Address Space Layout Randomization)關閉時,start_brkbrk同時指向data/bss段的結束位置(end_data)
    • 當ASLR打開時,start_brk和brk同時指向data/bss段的結束位置(end_data)再加上一個隨機的brk偏移。
  • 上面的進程虛擬內存布局展示了,start_brk是堆段的開始位置 ,brk(program break)是堆棧的結束位置。

例子

/* sbrk, brk 例子 */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
        void *curr_brk, *tmp_brk = NULL;

        printf("Welcome to sbrk example:%d\n", getpid());

        /* sbrk(0) 獲取當前 program break 位置 */
        tmp_brk = curr_brk = sbrk(0);
        printf("Program Break Location1:%p\n", curr_brk);
        getchar();

        /* 使用 brk 增加 program break 位置 */
        brk(curr_brk+4096);

        curr_brk = sbrk(0);
        printf("Program break Location2:%p\n", curr_brk);
        getchar();

        /* 使用 brk 減小 program break 位置 */
        brk(tmp_brk);

        curr_brk = sbrk(0);
        printf("Program Break Location3:%p\n", curr_brk);
        getchar();

        return 0;
}
  • 在增加program break之前,輸出如下:

  • start_brk=brk=end_data=0x602000

  • 在增加program break之后,輸入如下:

  • start_brk=end_data=0x602000,brk=0x603000.

  • 可以觀察到堆段

00602000-00603000 rw-p 00000000 00:00 0                                  [heap]
  • 00602000-00603000是堆段的虛擬地址范圍
  • rw-p的標准含義是Read、Write、 NoeXecute、Private
  • 00000000 是文件偏移量,由於沒有映射任何文件所以為0
  • 00:00 是major/minor device number,由於沒有映射任何文件所以為0
  • 0是inode 也是沒有映射任何文件所以為0
  • 【heap】是堆段

mmap

  • malloc使用mmap創建一個私有匿名的映射段,這個映射段的主要目的是申請一塊(零值初始化的)新內存,並且這塊內存只能被調用的這個進程獨占使用。
/* 使用mmap系統調用做私有匿名映射的例子 */
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

void static inline errExit(const char* msg)
{
        printf("%s failed. Exiting the process\n", msg);
        exit(-1);
}

int main()
{
        int ret = -1;
        printf("Welcome to private anonymous mapping example::PID:%d\n", getpid());
        printf("Before mmap\n");
        getchar();
        char* addr = NULL;
        addr = mmap(NULL, (size_t)132*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (addr == MAP_FAILED)
                errExit("mmap");
        printf("After mmap\n");
        getchar();

        /* Unmap mapped region. */
        ret = munmap(addr, (size_t)132*1024);
        if(ret == -1)
                errExit("munmap");
        printf("After munmap\n");
        getchar();
        return 0;
}
  • 調用mmap之前:可以看到,屬於libc.so和ld-linux.so共享庫的內存映射段。

  • 調用mmap之后:如下我們可以看到,mmap映射的內存段已經從上圖紅色框內分配出去(0xe0000-0xbf000=0x21000).

  • 調用munmap之后,如下輸出可以看到mmap已經被解除映射了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM