我尝试从以下两个来源找出共享内存段的范围,即进程的内存布局中的内存映射段。
从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
确定数据段的最大大小。
内核根据这些限制检查堆栈扩展、mmap
和brk
(堆分配)。它还检查分配是否存在潜在冲突的段,因此这些段永远不会最终相互覆盖(例如,请参见对堆分配执行的检查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