进程的虚拟地址范围

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_structs,它有开始和结束指针来标记虚拟内存区域的开始和结束

非常感谢

【讨论】:

【参考方案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.cmm.h 开头。

如果您想在您的系统上进行探索,您可以在/proc/$pid/maps 中查看每个进程的内存映射。请参阅How do I read from /proc/$pid/mem under Linux? 了解更多信息。

【讨论】:

我认为 dlmalloc 派生类仍然使用brk() 进行特定阈值下的分配,尽管我承认我最近没有看过这个。 OTOH、IIRC、OpenBSD 每次分配都使用mmap()

以上是关于进程的虚拟地址范围的主要内容,如果未能解决你的问题,请参考以下文章

《Linux内核设计与实现》读书笔记(十五)- 进程地址空间(kernel 2.6.32.60)

腾讯面试:linux内存性能优化总结

腾讯面试:linux内存性能优化总结

进程与线程的问题

虚拟内存与进程地址空间

虚拟地址