根据Linux程序员手册:

Brk()和sbrk()改变程序中断的位置 定义进程数据段的结束。

这里的数据段是什么意思?它只是数据段还是数据、BSS和堆的组合?

根据维基数据段:

有时数据、BSS和堆区域被统称为“数据段”。

我认为没有理由只改变数据段的大小。如果它是数据,BSS和堆,那么它是有意义的,因为堆将获得更多的空间。

这就引出了我第二个问题。到目前为止,在我读过的所有文章中,作者都说堆向上增长,堆栈向下增长。但是他们没有解释当堆占用了堆和栈之间的所有空间时会发生什么?


当前回答

Malloc使用BRK系统调用来分配内存。

包括

int main(void){

char *a = malloc(10); 
return 0;
}

用strace运行这个简单的程序,它将调用BRK系统。

其他回答

Malloc使用BRK系统调用来分配内存。

包括

int main(void){

char *a = malloc(10); 
return 0;
}

用strace运行这个简单的程序,它将调用BRK系统。

在您发布的图表中,“break”(由brk和sbrk操作的地址)是堆顶部的虚线。

The documentation you've read describes this as the end of the "data segment" because in traditional (pre-shared-libraries, pre-mmap) Unix the data segment was continuous with the heap; before program start, the kernel would load the "text" and "data" blocks into RAM starting at address zero (actually a little above address zero, so that the NULL pointer genuinely didn't point to anything) and set the break address to the end of the data segment. The first call to malloc would then use sbrk to move the break up and create the heap in between the top of the data segment and the new, higher break address, as shown in the diagram, and subsequent use of malloc would use it to make the heap bigger as necessary.

Meantime, the stack starts at the top of memory and grows down. The stack doesn't need explicit system calls to make it bigger; either it starts off with as much RAM allocated to it as it can ever have (this was the traditional approach) or there is a region of reserved addresses below the stack, to which the kernel automatically allocates RAM when it notices an attempt to write there (this is the modern approach). Either way, there may or may not be a "guard" region at the bottom of the address space that can be used for stack. If this region exists (all modern systems do this) it is permanently unmapped; if either the stack or the heap tries to grow into it, you get a segmentation fault. Traditionally, though, the kernel made no attempt to enforce a boundary; the stack could grow into the heap, or the heap could grow into the stack, and either way they would scribble over each other's data and the program would crash. If you were very lucky it would crash immediately.

我不确定这个图中的512GB这个数字是从哪里来的。它意味着一个64位的虚拟地址空间,这与您所拥有的非常简单的内存映射不一致。真正的64位地址空间是这样的:

              Legend:  t: text, d: data, b: BSS

This is not remotely to scale, and it shouldn't be interpreted as exactly how any given OS does stuff (after I drew it I discovered that Linux actually puts the executable much closer to address zero than I thought it did, and the shared libraries at surprisingly high addresses). The black regions of this diagram are unmapped -- any access causes an immediate segfault -- and they are gigantic relative to the gray areas. The light-gray regions are the program and its shared libraries (there can be dozens of shared libraries); each has an independent text and data segment (and "bss" segment, which also contains global data but is initialized to all-bits-zero rather than taking up space in the executable or library on disk). The heap is no longer necessarily continous with the executable's data segment -- I drew it that way, but it looks like Linux, at least, doesn't do that. The stack is no longer pegged to the top of the virtual address space, and the distance between the heap and the stack is so enormous that you don't have to worry about crossing it.

断点仍然是堆的上限。然而,我没有展示的是,在黑色的某个地方,可能有几十个独立的内存分配,使用mmap而不是brk。(操作系统会尽量让它们远离brk区域,这样它们就不会碰撞。)

There is a special designated anonymous private memory mapping (traditionally located just beyond the data/bss, but modern Linux will actually adjust the location with ASLR). In principle it's no better than any other mapping you could create with mmap, but Linux has some optimizations that make it possible to expand the end of this mapping (using the brk syscall) upwards with reduced locking cost relative to what mmap or mremap would incur. This makes it attractive for malloc implementations to use when implementing the main heap.

数据段是内存中保存所有静态数据的部分,在启动时从可执行文件读取,通常为零填充。

堆放在程序数据段的最后。Brk()用于改变(扩展)堆的大小。当堆不能再增长时,任何malloc调用都将失败。