一个进程的虚拟地址范围

7
简而言之:进程的虚拟地址空间是连续的吗?
我需要了解内核为进程分配的虚拟地址。如果我所述有误,请纠正我。
在进程创建时,内核会为其分配虚拟内存,并将进程各个段的虚拟地址的起始位置和结束位置存储在task_struct中的mm_struct中。
现在假设一个进程的堆已经用完并且需要增加堆大小,调用brk()
如果虚拟地址范围是连续的,那么新分配的堆块是否是从最初为该进程分配的范围之外提供的?还是以使新块相邻于原块的方式分配?如果没有空间(因为内存映射段正在那里),它如何跟踪?
如果虚拟地址范围不连续,vm_struct如何跟踪堆(或任何其他段)的不同地址范围块?
您能否澄清一下我的概念?
3个回答

8
不,进程的虚拟地址空间不一定是连续的。在过去,进程通过 brk 获得内存,这确实强制使进程堆成为一块连续的内存区域。现在,内存分配是通过 mmap 完成的,可以逐页操作进程的虚拟内存页。
如果您对内核方面感到好奇,我推荐两个参考资料: 如果您想在系统上进行探索,可以查看/proc/$pid/maps中每个进程的内存映射。有关更多信息,请参见如何在Linux下从/ proc / $ pid / mem读取?

我认为dlmalloc的衍生版本仍然在某个阈值以下的分配中使用brk(),尽管我承认我最近没有看过这个。另一方面,如果我没记错的话,OpenBSD对于每个分配都使用mmap() - ninjalj

8
虚拟地址空间不是连续的。查看cat /proc/<pid>/mem的输出。
当启动一个进程时,内核为动态链接器和进程本身分配了几个映射。之后,动态链接器通过mmap()分配更多的映射,进程可以通过mmap()分配更多的映射并通过brk()扩展堆。在dlmalloc及其衍生版本上,malloc()使用brk()来分配小于阈值的空间,并使用mmap()来分配大于或等于该阈值(约128K IIRC)的空间。
无论如何,在调用mmap()时,内核通常会将内存映射到堆远离的位置,因此通常有足够的空间来扩展堆。如果没有剩余的虚拟地址空间来扩展堆,则brk()将失败。

1
你应该首先查看/proc/<pid>/maps的内容,Suppie。 - Thomas M. DuBuisson

1

谢谢...

根据我的理解,虚拟地址空间在整个进程中并不是连续的,甚至在给定的内存段中也不是连续的。不同的虚拟地址范围块使用一个AVL树来管理,这个树被称为vm_area_struct(虚拟内存区域),从而可以轻松地将虚拟内存区域的块添加和删除到进程的task_struct中。参考:Virtual Memory。但是,虚拟内存区域本身是连续的。

也就是说,实际上task_struct包含指向mm_struct的指针,mm_struct包含指向AVL树头部的指针(每个内存区域一个树)。树的节点仅仅是vm_area_struct,它具有开始和结束指针来标记虚拟内存区域的开始和结束。

非常感谢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接