GLib中GThread Pool内存占用的问题

来源:互联网 发布:淘宝商城推广培训 编辑:程序博客网 时间:2024/05/16 13:48

最近,我们发现有个简单的程序内存占用特别大,该程序自启动开始就占用着2.7G左右的内存。最初,大家都觉得不可思议,因为这个程序功能非常简单:

1)它采用多socket多线程的方式,即每个socket链接都是一个线程,但该线程的功能很简单,就是持续接收socket数据。2)程序的另外一个功能就是转发数据。我排查了程序各处代码,没有发现有申请大块内存的地方,即便socket接收所采用的buffer,也不到1KB。

那是什么东西吃掉了2.7G的内存?

(1)继续排查,因为我们采用了GLib库,所以此处暂且将线程变小。结果发现,内存占用小了很多。

(2)分别测试1,10,20,40,80个线程时,内存占用情况,发现每增加一个线程,基本上会增加9M内存左右。

(3)定位问题。从(2)可以看出,问题出在线程上,我首先想到应该是线程堆栈大小出了问题,于是做了一个简单的测试:使用ulimit -s查看到当前系统设置的堆栈大小为10240(即10M),那么当我通过ulimit -s 5120之后,发现那个简单程序占用内存将之了1.3G。

OK,到这里问题就清楚了。GThread Pool在创建线程时,采用的是系统默认堆栈大小(如果需要设置堆栈大小,需要开启编译条件,并设置一个环境变量)。而不知道是谁设置了系统默认堆栈为10240,从而导致简单程序在多线程时内存占用巨大。

昨天写了更正此问题的方式(1.重新编译库。2.显示指定线程栈大小),但尝试之后发现在GThread Pool里都不可行。根据GThread Pool的官方说明:之所以每个线程都采用默认栈大小,是要解决多个Thread Pool公用线程的情况:如果线程的栈大小不一致,会导致无法在多个Thread Pool中被使用到。事实上,在GThread Pool代码中(glib-2.34.0),deprecated目录含有可指定堆栈大小的接口(gthread-deprecated.c),不过已被废弃。

目前我们的代码中,只采用了一个GThread Pool,所以不会出现多个Thread Pool共用线程的情况。即便如此,我也找不出方法去设置GThread Pool中线程的栈大小(要修改库代码的除外)。

官方还给出了一个可选择的方法,自己基于GAsyncQueue实现可指定堆栈大小的Thread Pool。这个办法略显繁琐,但也是一种可行的方式。当然,为了不修改库代码,需要在库上封装一层,以实现我们所需的可指定线程栈大小的Thread Pool。

原创粉丝点击