brk和sbrk

在计算机程序中,“program break”通常指的是堆的当前内存边界。当我们改变堆的大小(即分配或释放内存),其实就是在命令内核改变进程的“program break”位置。

最初,“program break”正好位于未初始化数据段(bss)末尾之后。当“program break”的位置抬升后,程序可以访问新分配区域内的任何内存地址,而此时物理内存页尚未分配。这就是“program break”的基本含义和作用。

  1. 进程可以通过增加堆的大小来分配内存,堆是一段长度可变的连续虚拟内存,始于进程的未初始化数据段末尾,随着内存的分配和释放而增减(见下图)。通常将堆的当前内存边界称为“program break”。

  2. 改变堆的大小(即分配或释放内存),其实就是命令内核改变进程的program break位置。最初,program break正好位于未初始化数据段末尾之后(如下图所示,与&end位置相同)。

  3. 在program break的位置抬升后,程序可以访问新分配区域内的任何内存地址,而此时物理内存页尚未分配。内核会在进程首次试图访问这些虚拟内存地址时自动分配新的物理内存页。

  4. 并不降低program break的位置,而是将这块内存添加到空闲内存列表中,供后续的malloc循环使用。

brk和sbrk_第1张图片


在计算机程序中,“program break”是影响内存分配的关键因素。以下是一些详细的解释:

  • 堆的大小:进程可以通过增加堆的大小来分配内存,堆是一段长度可变的连续虚拟内存,始于进程的未初始化数据段末尾,随着内存的分配和释放而增减。通常将堆的当前内存边界称为“program break”。

  • 改变堆的大小:改变堆的大小(即分配或释放内存),其实就是命令内核改变进程的“program break”位置。最初,“program break”正好位于未初始化数据段末尾之后。

  • 访问新分配的内存:在“program break”的位置抬升后,程序可以访问新分配区域内的任何内存地址,而此时物理内存页尚未分配。内核在进程首次试图访问这些虚拟内存地址时自动分配新的物理内存页。

  • 系统调用:传统的 UNIX 系统提供了两个操作“program break”的系统调用:brk()sbrk(),在 Linux 中依然可用。虽然代码中很少直接使用这些系统调用,但了解它们有助于弄清内存分配的工作过程。


brk()sbrk()都是用来改变程序的“program break”的位置,也就是改变数据段的长度,实现虚拟内存到物理内存的映射。

brk()函数通过传递的地址addr来重新设置program break,成功则返回0,否则返回-1。你可以把它想象成一个标记,你告诉系统:“嘿,我想把我的数据段结束的地方设在这里。”如果系统认为这个地方合适,就会把数据段的结束位置设在那里,否则就会告诉你失败。

sbrk()函数则是用来增加heap的大小,增加的大小通过参数increment决定,返回增加大小前的heap的program break,如果increment为0则返回program break。你可以把它想象成一个推车,你告诉系统:“嘿,我想把我的数据段向后推这么多。”系统就会把数据段向后推,然后告诉你原来的结束位置在哪里。

总的来说,brk()sbrk()都是用来管理内存的,但是他们的使用方式和场景有所不同。在开发中,一般用sbrk()来分配内存,用brk()来回收内存。


program break 是虚拟内存中数据段的结束位置, malloc 通过调用 brk 或 sbrk 增加 program break 的值,从而创建可以通过 malloc 动态分配的内存空间。 所以堆是进程的数据段的延伸。


当内存分配不够时,你可以使用sbrk()来增加heap的大小。sbrk()函数通过参数increment来增加heap的大小,返回增加大小前的heap的program break。如果increment为0则返回program break。你可以把它想象成一个推车,你告诉系统:“嘿,我想把我的数据段向后推这么多。”系统就会把数据段向后推,然后告诉你原来的结束位置在哪里。

以下是一个使用sbrk()来分配内存的示例:

#include 
#include 

int main() {
    int *p1 = sbrk(4); // 分配4个字节的内存空间
    printf("p1=%p\n", p1);

    int *p2 = sbrk(4);
    int *p3 = sbrk(4);
    int *p4 = sbrk(4);

    printf("p2=%p\n", p2);
    printf("p3=%p\n", p3);
    printf("p4=%p\n", p4);

    sbrk(-12); // 释放12个字节的内存空间

    int *cur = sbrk(0); // 获取sbrk后台的当前位置
    printf("cur=%p\n", cur);

    sleep(15);

    sbrk(4092 + 1);
    while (1);
}

这个示例可以帮助你理解如何使用sbrk()来分配内存。

参考链接:

  • brk和sbrk所指的program break到底是什么
  • 虚拟内存探究 – 第四篇:malloc, heap & the program break

你可能感兴趣的:(我的博客,linux)