brk與sbrk

linux系統中的brk 和sbrk 

#include<unistd.h>

int brk(void *addr);
void *sbrk(intptr_t increment);

根據Linux man手冊中的描述,brk和sbrk函數用於改變program break的位置,program break 定義了程序數據段的結束。舉例來說就是未初始化數據段結尾後的第一個地址,增加program break的值就是在給進程分配內存,反之,則是回收內存。當addr的值是一個合理的值(系統有足夠的內存,進程沒有超出它的最大數據段大小)時,brk()設置addr 指向的位置爲數據段的結尾。sbrk()會根據increment的值調整進程的數據空間,可令increment的值爲0來獲取當前進程program break的program break的值。

在Linux的系統調用中brk執行成功返回新的program break, 否則返回當前的program break。而在glibc中對brk進行了封裝,使其執行成功返回0, 失敗返回-1,並置errno 爲ENOMEM。爲了增加程序的可移植性,推薦使用malloc和free函數去申請或者釋放內存。


上述內容的意思可簡要概括爲兩句話:

  1. 系統調用brk可根據參數直接指定進程內存空間中堆段的結束位置
  2. 庫函數可根據參數調整進程內存空間中堆段的結束位置,當參數爲0時,返回堆空間當前的結束位置
對上述結論進行驗證:

#include<stdio.h>

int global; // a undefine variable store in bss segment

int main(void){
        int i = 9;
        int bss_heap_gap;

        int *heapvar, *heapvar2, *heapvar3;

        heapvar = (int*) malloc(sizeof(int));
        if(heapvar == NULL){
                perror("malloc");
                exit(-1);
        }

        heapvar2 = (int*) malloc(sizeof(int));
        if(heapvar2 == NULL){
                perror("malloc");
                exit(-1);
        }
        printf("address of first allocation is %x\n", (long)heapvar);
        printf("address of second allocation is %x\n", (long)heapvar2);

        printf("Current location of program break is %x\n", sbrk(0));
        printf("size of heap is %x\n", (long)sbrk(0) - (long)heapvar);

        sbrk(0x20);
        printf("sbrk(0x20);\n");
        printf("size of heap is %x\n", (long)sbrk(0) - (long)heapvar);

        brk((long)sbrk(0) - 0x30);
        printf("brk((long)sbrk(0) - 0x30);\n");
        printf("size of heap is %x\n", (long)sbrk(0) - (long)heapvar);

        heapvar3 = (int*) malloc(sizeof(int));
        if(heapvar3 == NULL){
                perror("malloc");
                exit(-1);
        }
        printf("address of allocation after brk((long)sbrk(0) - 0x30) is %x\n", (long)heapvar3);

        free(heapvar);
        free(heapvar2);
        free(heapvar3);

        return 0;
}

上述例子,已第一次動態申請內存時得到的內存空間起始位置作爲堆段的起始地址,在sbrk和brk函數的執行之後觀察堆空間的大小變化。

上述例子的一次輸出結果如下所示:

address of first allocation is 804b008
address of second allocation is 804b018
Current location of program break is 806c000
size of heap is 20ff8
sbrk(0x20);
size of heap is 21018
brk((long)sbrk(0) - 0x30);
size of heap is 20fe8
address of allocation after brk((long)sbrk(0) - 0x30) is 804b028

補充:有些材料中介紹brk函數是用來修改堆中申請空間的起始值,這個結論是不正確的,詳見例子中的變量heapvar3, 其值並不是brk設置的(long)sbrk(0) - 0x30 = 0x806bff0, 而是 0x804b028.

由heapvar2、和heapvar3可以看出堆空間的增長方向是由低地址向高地址增長。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章