堆地址范围内全局变量的地址
Posted
技术标签:
【中文标题】堆地址范围内全局变量的地址【英文标题】:Address of a Global Variable in the Heap Address Range 【发布时间】:2019-06-01 07:48:39 【问题描述】:我正在调试MPlayer-1.3.0
源代码,我看到一个全局变量,其地址(由GDB
甚至简单的打印返回)在堆分配范围内,而不是数据部分。我使用procfs
检查了堆范围。
555555554000-555555834000 r-xp 00000000 08:12 798876 /usr/bin/mplayer
555555a33000-555555b25000 r--p 002df000 08:12 798876 /usr/bin/mplayer
555555b25000-555555b2b000 rw-p 003d1000 08:12 798876 /usr/bin/mplayer
555555b2b000-555556479000 rw-p 00000000 00:00 0 [heap]
7fffc3fff000-7fffc8000000 rw-s 00000000 00:16 1932 /dev/shm/pulse-shm-3887887751
变量定义为int verbose = 0;
,位于mp_msg.c
的line 40
,地址为0x555555b3bbb0
,在[heap]
映射中。我什至检查了它之前和之后的一些变量定义:
int mp_msg_levels[MSGT_MAX]; // verbose level of this module. initialized to -2
int mp_msg_level_all = MSGL_STATUS;
int verbose = 0;
int mp_msg_color = 0;
int mp_msg_module = 0;
其中,只有mp_msg_level_all
位于数据部分。任何帮助表示赞赏。
【问题讨论】:
【参考方案1】:假设您的问题是“为什么根据/proc/self/maps
分配给[heap]
内存映射的int verbose = 0;
?”,答案是这样的
-
整个
[heap]
概念实际上是早已被遗忘的过去的遗物,并且
传统的[heap]
紧跟在.bss
之后,它们通常共享相同的映射,所以这里没什么值得惊讶。
稍微扩展一点,在旧的传统 UNIX 内存模型中(在线程和 mmap
成为事物之前),在堆栈向下增长的处理器上,内存的上半部分保留给内核空间,堆栈从用户内存的最高端开始,程序.text
本身从地址0开始,紧随其后的是.data
和.bss
,然后是堆(brk
/sbrk
种类)。这允许堆增长到更高的地址,并为组合堆+堆栈提供最大可用内存。
在存在线程、共享库和内存映射文件的情况下,该模型根本无法正常工作,并且在很大程度上已被现代 malloc
实现所抛弃,这些实现几乎不会打扰 sbrk
。相反,他们只是 mmap
他们需要的内存(并且任何此类内存都不会显示在 [heap]
中,您在 procfs
中看到)。
附言
将零页映射到进程空间的想法早已被放弃,因为它只会导致错误。这就是为什么.text
在所有现代 UNIXen 上都从更高的地址开始。
给内核一半的可用地址空间也是相当浪费的,32 位 Linux 开始给内核提供更少的空间。在 64 位系统上,地址空间不足不再是问题。
更新:
所以你的意思是 [heap] 包含 .bss 和堆的一部分。那么,确定地址是否在堆内的唯一方法是跟踪 malloc(),free(),... 调用?
我觉得我解释得不好。
在进程空间中有一个称为“堆”的区域的概念已经过时。现代的malloc
实现可能有多个线程特定的arenas,通过mmap
从系统获得,堆分配的对象可以在其中任何一个中。
你不能轻易地说“哦,这个地址 0x568901234 看起来像堆”,因为它可以是任何东西。
如果 procfs 输出已过时,在 Linux 中确定进程的虚拟内存区域(例如 .text、heap 和 .bss)的地址范围的标准方法是什么?
在这里,您再次尝试用有些过时的术语来解释内存布局:在大多数进程中没有.text
或.bss
,因为每个共享库都会有它自己的(除了主要的可执行文件)。还有许多附加部分(.tls
、.plt
、.got
等)而且部分甚至都不是必需的 em> 在运行时——ELF(在运行时)只需要段,而不关心段。
【讨论】:
感谢@used-russian。所以你的意思是[heap]
包含.bss
和heap
的一部分。那么,确定地址是否在堆内的唯一方法是跟踪malloc(),free(),...
调用?我说的对吗?
One more question:
确定Linux
中进程的虚拟内存区域(例如.text
、heap
和.bss
)的地址范围的标准方法是什么,如果@ 987654355@ 输出已过时?
经验相对于普通知识的好处在你的回答中很明显,这表明你不是昨天从萝卜车上摔下来的:)
再次感谢。你知道在[heap]
对应的范围内只捕获动态数据访问(不是.bss
访问)的方法吗?【参考方案2】:
mp_msg_level_all
位于数据部分中,因为它已初始化为非零值。其余部分初始化为 0,因此属于 bss
部分。
为什么链接器决定将bss
放入我们可能想知道的明显堆地址范围内。
【讨论】:
以上是关于堆地址范围内全局变量的地址的主要内容,如果未能解决你的问题,请参考以下文章