Linux中进程/线程的大小

4

在Linux中,进程/线程的大小是多少?当创建进程/线程时,除了task_struct和其他内部数据结构外,还有什么?

一个进程/线程的栈是在初始化(固定大小)时分配的吗?还是在需要时(如虚拟内存)分配的?

当一个标准进程/线程在内存中被创建时,我如何知道它的大小?

2个回答

3
在Linux中,当一个大块内存(>pagesize = 4096字节)首次分配时,它会使用特殊的“空”内存页面在页面表中,这些页面没有任何支持,因此当启动线程时,将为线程堆栈分配约1 MB的这些零页面。随着堆栈的增长,页面被转换为实际支持的内存页面。由于这个“null”页支持,通常可以拥有自由的大堆栈。
线程和进程都是使用相同的底层系统调用clone(2)创建的。它有很多选项和功能。详细解释请参见man clone http://linux.die.net/man/2/clone 大块内存是通过匿名的mmap(2)调用分配的。
您还可能对进行网络搜索“linux overcommit bit”感兴趣。
(如果您想精确您的问题,我可以更具体地回答。)

谢谢。因此,每个线程都保留了1MB的堆栈大小。但是,您说只有在真正需要时才分配线程的内存,这意味着直到线程向内存写入内容之前,物理内存不会失去另外的1MB,对吗?如果是这种情况,考虑我的内核为50MB(例如),而我的内存为70MB,我是否仍然可以分配超过20个线程?或者内核实际上会在物理内存中保留1MB? - Amumu
另外,当我输入uname -a时,我的堆栈大小限制为8192 kb。这是每个进程/线程的上限吗? - Amumu
难道在Linux上,每个进程不都会获得自己的页面表,这些表可以增长到几兆字节吗? - Hristo Iliev
1
堆栈最初是由空页面组成的,不使用物理内存。读取将返回0,写入将导致页面错误,使它们变为实际内存支持。假设您将第一个项目推送到堆栈上,只有第一页将使用总共4096字节的物理内存进行支持。一旦您推送超过4096字节,第2页将由物理内存支持-以此类推。因此,您可以看到堆栈仅使用其所需的大约物理内存量(在4096字节的粒度内)。 - Andrew Tomazos
kthread 怎么样?每个线程是否立即分配一个在 uname -r 中列出的固定堆栈大小? - Amumu
1
kthreads 用于内核内部使用(例如由设备驱动程序),不可从用户空间进程访问。很抱歉我对它们了解不多。我不知道 clone 系统调用是否会调用 start_kthread 来创建新的进程或线程,或者 kthread 是否是一个单独的内核设施。 - Andrew Tomazos

1

Andrew所说的是正确的,但这并不意味着您的线程/进程从创建时起就不会“使用内存”。为堆栈保留的空间始终会在您的进程中消耗虚拟地址空间,这意味着对于具有大型线程堆栈的32位机器而言,您很快就会用尽地址(仅使用glibc上的默认线程堆栈大小,大约300个线程将耗尽虚拟地址空间)。此外,堆栈会对提交费用做出贡献,该费用确定禁用超额提交时可以分配的总内存量。

Linux默认为主线程的堆栈预先提交128k,并允许在提交费用未耗尽的情况下自动获取更多。线程堆栈完全由用户空间(在大多数Linux系统上为glibc/NPTL)分配,并且无法超出其初始大小。根据版本和系统设置,glibc/NPTL通常默认为每个线程分配2 MB至10 MB之间的某个值。


谢谢。uname -a 显示的 kbytes 中的堆栈大小是多少?最终,线程的大小是 thread_info struct 的大小 + kernel stack (8KB) + thread stack (user stack, 2MB~10MB) 的大小? - Amumu
这是关于32位虚拟地址空间耗尽的一个好观点。我生活在64位领域,这不是一个问题。 - Andrew Tomazos

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