【问题标题】:Pthreads - High memory usagePthreads - 高内存使用
【发布时间】:2026-01-11 14:35:01
【问题描述】:

我正在用 C 语言编写一些东西,在 256Mb 系统上的 Linux 中创建大量 Pthread。我通常有 +200Mb 的免费空间。

当我使用少量线程运行程序时,它可以工作,但是一旦我让它创建大约 100 个线程,它就会出现错误,因为系统内存不足。我做了几个测试,每个线程都使用了将近 2Mb。线程的堆栈大小设置为 16Kb。

我用来创建每个线程的代码:

pthread_attr_t attr;
pthread_attr_init(&attr);
size_t stacksize;
stacksize = (double) 16*1024;
int res = pthread_attr_setstacksize (&attr, stacksize);
int res2 = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (res != 0 || res2 != 0) {
    logs << "pthread_attr_XX: error "+int2string(res);
    exit(-1);
}
pthread_t id;
pthread_create(&id, &attr, &Class::thread_callback, &some_var);

这是正常的还是我错过了什么?谢谢。

【问题讨论】:

  • 您确定您的系统内存不足,还是您的其他资源(可能是线程描述符)不足?
  • @mah:线程描述符在 Linux 中不太可能出现,因为在幕后,它们就像大多数事情的完整进程一样被处理并从进程 ID 池中获取,直到用完为止。更有可能是内存问题是由堆上创建的东西和堆空间耗尽引起的。
  • 线程在做什么?您可能需要重新考虑在内存资源如此有限的机器上生成 100 个线程的设计。也许看看select()
  • @mah,是的,我可以在其他终端中看到使用的内存增加直到用完。
  • 是否使用了 TLS(带有 __thread 说明符的数组)?这也可以来自图书馆。您的线程使用 malloc 的大量内存吗? res中真的没有返回错误吗?你的值正好是最大的禁止值according to line 74 of this file。检查是“/* Catch invalid sizes. */\nif (stacksize &lt; PTHREAD_STACK_MIN)\nreturn EINVAL;

标签: c linux multithreading pthreads memory-efficient


【解决方案1】:

不确定它是否会有所帮助,但请尝试在创建第一个线程之前使用 RLIMIT_STACK 调用 setrlimit 以将堆栈大小限制为 16k。

【讨论】:

  • 16 kb 可能太小了,ulimit -s 40ulimit -s 70 也应该试试。
  • @osgx:你建议的命令成功了,谢谢。我没有尝试使用 setrlimit,但我想它也会起作用,因为它基于相同的。现在我可以打开很多内存使用率低的线程。看起来 pthread_attr_setstacksize 没有按预期工作,需要更改全局限制
【解决方案2】:

系统线程库并非旨在支持内存非常有限的系统上的大量线程。您需要使用专为此目的设计的线程库,或者最好使用更少的线程。

【讨论】:

    【解决方案3】:

    是的,几乎任何操作系统都在这么多线程上阻塞和死机是很常见的。这不是操作系统制造商(Linux 或其他)所关注的问题,因为很少有系统拥有这么多 CPU,因此使用 100 个线程的代码执行速度可能不会比使用 8 个线程(或者你使用多少 CPU)快得多有)。

    我认为您需要做的是某种线程池。我也怀疑如果你真的需要那么多线程,这个页面上的 ulimit 答案会很有用,但就像我说的,我认为在大多数情况下,很多线程不会让你得到很多,如果你在程序中而不是在程序中修复它系统,它会让它更便携。

    【讨论】:

      【解决方案4】:

      为什么是stacksize = (double) 16*1024;?是整数。

      尝试将其设置为 32 或 64 KB,因为可能不允许 16*1024;堆栈中也可以有 TLS(即使您不使用 TLS;库会使用,包括 libc)。

      所以,将行改为

      stacksize = 64*1024; 
      

      并检查消耗了多少内存。

      【讨论】:

        【解决方案5】:

        如果您想降低开销,请考虑使用用户空间线程技术,例如光纤、ala 协作任务管理。

        http://en.wikipedia.org/wiki/Fiber_(computer_science)

        http://www.evanjones.ca/software/threading.html

        GNU 可移植线程:

        http://www.gnu.org/software/pth/

        Boost C++ 协程:

        http://www.boost.org/doc/libs/1_60_0/libs/coroutine/doc/html/index.html

        仅限 Windows 的纤程仅供参考:

        http://msdn.microsoft.com/en-us/library/ms682661(v=vs.85).aspx

        有关更多示例实现,请参阅 Wikipedia 链接。

        【讨论】:

          【解决方案6】:

          可能是这个原因:

          "(识别泄漏

          如果您创建了一个可加入线程但忘记加入它,它的资源或私有内存将始终保存在进程空间中并且永远不会回收。始终加入可连接的线程;如果不加入它们,您将面临严重的内存泄漏风险。)”

          在这里阅读: http://www.ibm.com/developerworks/library/l-memory-leaks/

          【讨论】:

          • 我不认为问题在于 OP 没有加入线程。问题与创建线程时使用的内存量有关。