内存映射段和堆会一直增长直到它们相遇吗?

内存映射段和堆会一直增长直到它们相遇吗?

我尝试从以下两个来源找出共享内存段的范围,即进程的内存布局中的内存映射段。


https://manybutfinite.com/post/anatomy-of-a-program-in-memory/,我找到了一个进程的内存布局图

内存映射段和堆会一直增长直到它们相遇吗?

或者两个段的增长是否有限制,类似于堆栈段的 RLIMIT_STACK?

在此输入图像描述


来自 Linux 编程接口

为了留出堆和堆栈增长的空间,共享内存段从虚拟地址 0x40000000 开始附加。映射映射(第 49 章)和共享库(第 41 章和 42 章)也放置在该区域中。 (共享内存映射和内存段的默认放置位置存在一些变化,具体取决于内核版本和进程的 RLIMIT_STACK 资源限制的设置。)地址 0x40000000 被定义为内核常量 TASK_UNMAPPED_BASE。

共享内存段是否从 TASK_UNMAPPED_BASE 开始并向上增长?

请注意,上图显示共享内存段向下增长,那么它是向上增长还是向下增长呢?

在此输入图像描述

谢谢。

答案1

有一些限制适用于mmap段和堆段。RLIMIT_AS确定总体可用地址空间;这涵盖了程序可以进行的所有内存分配。RLIMIT_DATA确定数据段的最大大小。

内核根据这些限制检查堆栈扩展、mmapbrk(堆分配)。它还检查分配是否存在潜在冲突的段,因此这些段永远不会最终相互覆盖(例如,请参见对堆分配执行的检查brk)。如果分配不可能,程序会被适当地“通知”:C 库返回一个ENOMEM错误,如果堆栈无法扩展,brk内核会用 a 杀死程序...SIGSEGV

共享内存段(严格来说,从内核角度来看,虚拟内存区域)如何增长取决于内存布局,从一个进程到另一个进程,内存布局可能非常不同。在大多数架构上,“传统”内存映射导致自下而上的分配,从TASK_UNMAPPED_BASE;开始。非传统内存映射导致自上而下的分配。看arch_pick_mmap_layout()mmap_is_legacy()以 x86 架构为例。您可以使用setarch's标志切换到旧内存映射-L(请参阅下面的示例)。

在实践中,您可以通过查看/proc/$$/maps和检查加载的共享库(如果有)的地址及其加载顺序来了解段如何增长。动态链接器总是首先加载;如果它的地址低于其他库,则分配是自下而上的,否则是自上而下的。比较64 位 x86 系统上cat /proc/self/maps的输出。setarch x86_64 -L cat /proc/self/maps

相关内容