进程的虚拟地址范围
Posted
技术标签:
【中文标题】进程的虚拟地址范围【英文标题】:Virtual address range of a process 【发布时间】:2011-08-21 03:54:36 【问题描述】:简而言之:进程的虚拟地址空间是连续的吗?
我需要了解内核分配给进程的虚拟地址。如果我在继续时有错误,请纠正我。
在进程创建时,内核为进程分配虚拟内存,并将进程不同段的虚拟地址的开始和结束存储在mm_struct
中的task_struct
中。
现在说a进程用完了堆,需要增加堆大小。调用brk()
。
如果虚拟地址范围是连续的,那么新分配的堆块是从最初为此进程分配的范围之外提供的吗?还是以新块与原始块相邻的方式分配。如果没有空间怎么办(因为内存映射段就在那里)。它是如何被跟踪的?
如果虚拟地址范围不连续,vm_struct
如何跟踪堆(或任何其他段)的地址范围的不同块?
你能澄清一下我的概念吗?
【问题讨论】:
【参考方案1】:谢谢.. 根据我的理解阅读了上述文献后,
虚拟地址空间在整个进程中不连续,甚至在给定的内存段中也不连续。并且虚拟地址范围的不同块在内核中使用vm_area_struct
(虚拟内存区域)的 AVL 树进行管理。从而轻松地向进程的task_struct
添加和删除虚拟内存区域 块。参考:Virtual Memory。但虚拟内存区域本身是连续的。
即实际上,task_struct
包含指向 mm_struct
的指针,其中包含指向 AVL 树头的指针(每个内存区域一棵树)。树的节点只不过是vm_area_struct
s,它有开始和结束指针来标记虚拟内存区域的开始和结束
非常感谢
【讨论】:
【参考方案2】:虚拟地址空间不连续。查看cat /proc/<pid>/mem
的输出。
当启动一个进程时,内核会为动态链接器和进程本身分配多个映射。之后,动态链接器通过mmap()
分配更多的映射,进程可以通过mmap()
分配更多的映射并通过brk()
扩展堆。 dlmalloc 和衍生工具上的malloc()
使用brk()
用于小于阈值的分配,mmap()
用于大于或等于该阈值(大约 128K IIRC)的分配。
无论如何,在调用mmap()
时,内核通常会将内存映射到远离堆的地方,因此通常有足够的空间来扩展堆。如果没有剩余的虚拟空间来扩展堆,brk()
将失败。
【讨论】:
/proc/<pid>/maps
的内容可能是您应该首先查看的内容,伙计。【参考方案3】:
不,进程的虚拟地址空间不一定是连续的。在过去,一个进程通过brk
获取内存,这确实迫使进程堆成为一个连续的内存区域。现在内存分配是通过mmap
来完成的,可以逐页操作进程的虚拟内存。
如果您对内核方面的事情感到好奇,我推荐两个参考资料:
阅读有关 Linux 内核的书籍,例如 Linux Device Drivers by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman,尤其是 chapter 8 (Allocating Memory)。 通过LXR, the Linux kernel cross-reference浏览内核代码。内存管理代码在mm
directory;以mmap.c
或mm.h
开头。
如果您想在您的系统上进行探索,您可以在/proc/$pid/maps
中查看每个进程的内存映射。请参阅How do I read from /proc/$pid/mem under Linux? 了解更多信息。
【讨论】:
我认为 dlmalloc 派生类仍然使用brk()
进行特定阈值下的分配,尽管我承认我最近没有看过这个。 OTOH、IIRC、OpenBSD 每次分配都使用mmap()
。以上是关于进程的虚拟地址范围的主要内容,如果未能解决你的问题,请参考以下文章