我正在调试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;
,位于line 40
的{{1}}处,地址为mp_msg.c
,位于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;
位于数据部分。任何帮助表示赞赏。
答案 0 :(得分:5)
假设您的问题是“为什么根据int verbose = 0;
将[heap]
分配给/proc/self/maps
内存映射?”的答案是
[heap]
概念实际上是遗忘已久的过去的遗物,并且[heap]
在.bss
之后立即开始,并且它们通常共享相同的映射,因此这里没有什么让我们感到惊讶的。在旧的传统UNIX内存模型中(在线程和mmap
成为问题之前),在点1上稍微扩展了一点,在堆栈变小的处理器上,内存的上半部分留给了内核空间,堆栈从用户内存的最高端开始,程序.text
本身从地址0开始,紧接着是.data
和.bss
,然后进行堆(brk
/ sbrk
种)。这样可以使堆增长到更高的地址,并为合并的堆+堆提供最大的可用内存。
在存在线程,共享库和内存映射文件的情况下,该模型根本无法很好地工作,并且已被现代malloc
实现方式大量抛弃,而这些实现方式几乎很少困扰sbrk
。取而代之的是,它们只是mmap
所需的内存(并且您在[heap]
中看到的procfs
中不会显示任何此类内存)。
P.S。
.text
在所有现代UNIXen上都从更高地址开始的原因。更新:
因此,您的意思是[heap]同时包含.bss和部分堆。因此,确定地址是否在堆中的唯一方法是跟踪malloc(),free(),...调用?
我认为我的解释不太好。
在进程空间中只有一个称为“堆”的区域的概念已过时。现代的malloc
实现很可能具有多个通过mmap
从系统获取的线程特定的竞技场,并且堆分配的对象可以位于其中的任何一个中。
您不能轻易说“哦,这个地址0x568901234看起来像堆”,因为它可以是任何东西。
在Linux中,如果procfs输出已过时,确定虚拟内存区域(例如.text,heap和.bss)的地址范围的标准方法是什么?
再一次,您尝试用有些过时的术语来解释内存布局:大多数进程中没有 一个.text
或.bss
,因为每个共享库将具有自己的库(除了主要的可执行文件库之外)。而且还有许多其他部分(.tls
,.plt
,.got
等),和部分甚至没有完全在运行时必需 - ELF(在运行时)仅需要段,而不关心节。
答案 1 :(得分:1)
mp_msg_level_all
在数据部分中,因为它已初始化为非零值。其余部分初始化为0,因此属于 bss
部分。
为什么链接器决定将bss
放入我们可能只想知道的显然是堆地址的范围内。