堆地址范围内的全局变量的地址

时间:2019-01-06 11:17:41

标签: c heap-memory mplayer memory-layout

我正在调试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; 位于数据部分。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:5)

假设您的问题是“为什么根据int verbose = 0;[heap]分配给/proc/self/maps内存映射?”的答案是

  1. 整个[heap]概念实际上是遗忘已久的过去的遗物,并且
  2. 传统的[heap].bss之后立即开始,并且它们通常共享相同的映射,因此这里没有什么让我们感到惊讶的。

在旧的传统UNIX内存模型中(在线程和mmap成为问题之前),在点1上稍微扩展了一点,在堆栈变小的处理器上,内存的上半部分留给了内核空间,堆栈从用户内存的最高端开始,程序.text本身从地址0开始,紧接着是.data.bss,然后进行堆(brk / sbrk种)。这样可以使堆增长到更高的地址,并为合并的堆+堆提供最大的可用内存。

在存在线程,共享库和内存映射文件的情况下,该模型根本无法很好地工作,并且已被现代malloc实现方式大量抛弃,而这些实现方式几乎很少困扰sbrk 。取而代之的是,它们只是mmap所需的内存(并且您在[heap]中看到的procfs中不会显示任何此类内存)。

P.S。

  • 将零页面映射到进程空间的想法早已被放弃,因为它只会导致错误。这就是.text在所有现代UNIXen上都从更高地址开始的原因。
  • 给内核提供一半的可用地址空间也很浪费,并且32位Linux开始为内核提供更少的空间。在64位系统上,地址空间不足不再是问题。

更新

  

因此,您的意思是[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放入我们可能只想知道的显然是堆地址的范围内。