Pthreads - 高内存使用率

9
我正在使用C语言编写与Linux系统相关的IT技术内容,需要创建大量Pthreads,而我的系统只有256Mb内存。通常情况下,我会有超过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
1
@mah:在Linux中,线程描述符很不可能存在,因为在大多数情况下,它们在底层处理方式上与完整进程相同,并从进程ID池中获取,直到该池用尽。更有可能的是,内存问题是由于在堆上创建的东西耗尽了堆空间。 - diverscuba23
2
线程在做什么?在内存资源如此有限的机器上生成100个线程的设计可能需要重新考虑。也许可以看看 select() - Keith Layne
@mah,是的,我可以在其他终端看到使用的内存增加,直到用尽为止。 - NeDark
1
是否使用了TLS(带有__thread说明符的数组)?这可能来自库。你的线程从malloc中使用了很多内存吗?确实没有返回错误吗?你的值恰好是最大的禁止值根据此文件第74行。检查是"/* 捕获无效大小。 */\n if (stacksize < PTHREAD_STACK_MIN)\n return EINVAL;" - osgx
显示剩余2条评论
6个回答

4

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


2
16 kb 可能太小了,所以应该尝试 ulimit -s 40ulimit -s 70 - osgx
2
@osgx:你建议的命令解决了问题,十分感谢。虽然我没试过setrlimit,但是我猜它也能行,因为原理是一样的。现在我可以开启很多线程,并且内存占用率很低。看起来pthread_attr_setstacksize没有按预期工作,需要改变全局限制。 - NeDark

2

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


1

是的,对于几乎任何操作系统来说,在那么多线程上崩溃和死机都是相当普遍的。这不是操作系统制造商(包括Linux在内)关注的问题,因为很少有系统拥有那么多个CPU,所以你的代码使用100个线程执行与使用8个线程(或者你拥有的CPU数量)执行相比,速度不会快多少。

我认为你需要做的是一些线程池的处理。如果你真的需要那么多线程,我还怀疑这个页面上的ulimit答案会有用,但是像我说的,在大多数情况下,那么多的线程并不能带来太多好处,如果你在程序中修复它而不是在系统中修复它,它将使它更具可移植性。


1
为什么 stacksize = (double) 16*1024;?它是整数。
尝试将其设置为32或64千字节,因为16 * 1024可能不被允许;栈中也可以有TLS(即使您不使用TLS;库会使用,包括libc)。
所以,将该行更改为
stacksize = 64*1024; 

并检查消耗了多少内存。


0

如果您想要更低的开销,考虑使用用户空间线程技术,例如纤程,即协作式任务管理。

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

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

GNU Portable threads:

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

Boost C++ 协程:

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

关于仅适用于Windows的纤程(Fibers):

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

更多实例实现请查看维基百科链接。


-2
也许这就是原因:
"(识别泄漏
如果你创建了一个可加入的线程但忘记加入它,它的资源或私有内存将一直保留在进程空间中,永远不会被回收。请始终加入可加入的线程;如果不加入它们,可能会导致严重的内存泄漏。)"
在这里阅读: http://www.ibm.com/developerworks/library/l-memory-leaks/

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

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