给定进程中堆的界限是什么?我了解此问题可能没有简单的答案,因此我对以下具体答案感兴趣:

  • 在AMD64上的Linux下,对于64位进程是否有标准的堆大小/位置?
  • 如果我正在实现语言运行时,如何找出不允许放置堆的位置(同样,Linux/AMD64)
  • 应用程序是否可以通过一种便携式方式来确定其开始/结束的位置?
  • 最佳答案

    我假设您正在尝试在此处编写自己的堆分配器,并且从标记中假定您正在Linux中进行。

    SunEric为您提供了可能使用的内存的有用指示,但是,可以使用的内存是操作系统为您提供的内存。 IE要使内存进入您的进程,您将需要调用操作系统以将虚拟内存映射到进程空间(及其后的一些物理内存)。 malloc()为您对此进行抽象,并在C中实现“堆”。它可以通过两种方式获取其内存:

  • 使用brk系统调用(映射到C库brksbrk)
  • mmapMAP_ANON一起使用(或更准确地说,是底层系统调用mmap2)。
  • brk是为堆分配内存的经典方法,通常,当我们谈论“堆”时,我们是指以这种方式分配内存(尽管brk可以用于分配堆以外的内存,并且堆项目可能位于其他地方) - 见下文)。 Herebrk分配方式的一个很好的答案,我无法对其进行改进。内存使用的位置实际上是算术的结果。堆在加载时遵循程序的BSS-即BSS的值随着堆的扩展而增长,因此开始实际上是由OS和动态加载程序确定的。因此,堆的末端取决于堆的大小和堆的大小(即您将堆长到多大)。
    mmap不太清晰。它需要一个addr参数:



    因此,如果您使用mmap来获取特定堆项的空间(就像malloc可能特别适用于大型对象),则操作系统会选择其位置(带或不带提示)。如果您使用MAP_FIXED,它将为您提供确切的位置或失败。从这个意义上讲,您的堆(或其中的项目)可以在操作系统允许您映射内存的任何位置。

    您问是否有一种可移植的方法来找出堆的开始和结束位置。可移植意味着一种语言,我假设使用C。就brk类型堆而言,是的(可以移植)。 man end提供:



    由于堆从加载时的BSS的末尾运行到运行时的BSS的顶部,因此一种方法是将加载时的end的值作为堆的底部开始,并将end的值作为加载时的开始评估为堆的结尾。这会错过libc本身和共享库可能在调用main()之前分配内容的事实。因此,更保守的方法是说它是edataend之间的区域,尽管严格来讲,这可能包括不在堆上的内容。

    如果您不是在C语言中刻薄,则需要使用类似的技术。进行``程序中断''(即内存空间的顶部)并减去为堆分配的最低地址。

    如果要查看任意进程的堆的内存分配,请执行以下操作:
    $ cat /proc/$$/maps | fgrep heap
    01fe6000-02894000 rw-p 00000000 00:00 0                                  [heap]
    

    $$替换为您要检查的进程的PID。

    08-28 04:57