【问题标题】:Size of a process/thread in LinuxLinux中进程/线程的大小
【发布时间】:2023-03-08 05:05:01
【问题描述】:

Linux 中进程/线程的大小是多少?当一个进程/线程被创建时,连同task_struct 和其中的其他数据结构,还有什么其他的吗?

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

我如何知道标准进程/线程在内存中创建时的大小?

【问题讨论】:

    标签: c linux multithreading kernel


    【解决方案1】:

    当一大块内存(> pagesize = 4096 字节)在 Linux 上首次分配时,它会在页表中使用特殊的“空”内存页,这些内存页没有任何支持,所以当一个线程启动时,它会分配 ~这些零页中的 1 MB 用于线程堆栈。随着堆栈的增长,页面随后被转换为实际内存支持的页面。由于这种“空”页面的支持,通常可以有足够大的堆栈。

    线程和进程都是使用称为 clone(2) 的相同底层系统调用创建的。它有很多选择,可以做很多事情。详细解释见man clone

    http://linux.die.net/man/2/clone

    大块内存是通过匿名 mmap(2) 调用分配的。

    您可能也有兴趣在网络上搜索“linux overcommit bit”

    (如果你想完善你的问题,我可以更具体。)

    【讨论】:

    • 谢谢。因此,每个线程都为其堆栈大小保留 1MB。但是,您说线程的内存仅在真正需要时才分配,这意味着物理内存不会再损失1MB的物理内存,直到线程将某些内容写入内存,对吗?如果是这种情况,考虑我的内核是 50 MB(例如),我的内存是 70MB,我还能分配超过 20 个线程吗?还是内核实际上在物理内存中保留了 1MB?
    • 另外,当我输入 uname -a 时,我的堆栈大小限制为 8192 kb。这是每个进程/线程的上限吗?
    • Linux 上的每个进程不是都有自己的一组页表,可以增长到几 MB 吗?
    • 堆栈最初由空页组成,不使用物理内存。读取将返回 0,写入将导致页面错误,从而导致它们被实际内存支持。假设您将第一项压入堆栈,只有第一页将使用总共 4096 字节的物理内存进行备份。一旦推送超过 4096 字节,第 2 页将由物理内存支持 - 依此类推。所以你可以看到堆栈只使用了大约它需要的物理内存量(在 4096 字节的粒度内)。
    • kthreads 用于内核内部(例如通过设备驱动程序),并且不能从用户态进程访问。我对他们了解不多,抱歉。我不知道克隆系统调用是否调用 start_kthread 来创建一个新进程或线程,或者 kthread 是否是一个单独的内核设施。
    【解决方案2】:

    Andrew 说的是真的,但这并不意味着您的线程/进程从创建的那一刻起就不会“使用内存”。为堆栈保留的空间总是在您的进程中消耗虚拟地址空间,这意味着对于大型线程堆栈,您将很快用完 32 位机器上的地址(默认线程堆栈只有大约 300 个线程) glibc 上的 -size 将耗尽虚拟地址空间)。此外,堆栈会产生提交费用,这决定了在禁用过度使用时可以分配的内存总量。

    Linux 默认为主线程的堆栈预提交 128k,如果提交费用尚未用完,则允许自动获得更多。线程堆栈完全由用户空间(glibc/NPTL,在大多数 Linux 系统上)分配,并且不能超过其初始大小。根据版本和系统设置,glibc/NPTL 通常默认为每个线程分配 2 MB 到 10 MB 的空间。

    【讨论】:

    • 谢谢。 uname -a 显示的堆栈大小(以千字节为单位)是多少?最后一个线程的大小是thread_info struct + kernel stack (8KB) + thread stack (user stack, 2MB~10MB)的大小?
    • 这是一个关于 32 位虚拟地址空间耗尽的好点。我住在 64 位的土地上,这不是问题。
    猜你喜欢
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 2015-06-08
    相关资源
    最近更新 更多