Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2316091
  • 博文数量: 473
  • 博客积分: 12252
  • 博客等级: 上将
  • 技术积分: 4307
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-12 10:02
文章分类

全部博文(473)

文章存档

2012年(8)

2011年(63)

2010年(73)

2009年(231)

2008年(98)

分类: C/C++

2008-09-23 15:20:30


天解决了困扰我好久的一个问题:短信网关内存不断攀升(好像看似内存泄露)。兴奋之余,积极响应ds和小飞鱼的号召,把此问题分享出来。虽然可供参考的部分并不多,但是也有一定的反面教材意义:-)

问题描述:
原 有的短信网关,每产生一个socket连接,就会create一个或多个thread去处理这个socket上的数据收发(数据收发是在 CTCPConnection类中完成,这个类自动创建线程)。根据观察,每次有新连接时,内存都会固定增长20M,并且当连接断开(所有new出来的内 存也被释放了)之后,内存并不使用并没有降低。表现为“内存泄露”的现象。
另一个奇怪的现象是:该问题只出现在四川现场,在家里做测试并无异常。


初步分析:
此问题看似内存泄露,但实际肯定不是。因为程序里并没有哪个地方申请了20M的内存,并且经过细致检查new和delete,初步排除了内存泄露的可能。知觉将问题所定在操作系统的软件配置和环境设置上。


试验结果:
为了进一步找出问题,书写了如下代码:
int main(int argc,char *argv[])
{
        int i=0;
        char *szP=NULL;
        while(true){
                i++;
                szP=new char[10240];
                delete []szP;
                sleep(5);
        }
}
运行测试发现内存随有攀升,但是能够降下来,说明环境本身的new和delete执行都是正常的。考虑到短信网关中,每次内存攀升都是伴随着新socket连接而产生,而新socket连接会引起新线程的创建。
故修改测试代码如下:
void *testthread(void *)
{
        printf("I am working.\n");
        char *szP=NULL;
        szP=new char[10240];
        delete []szP;
        printf("I am stopping.\n");
        pthread_exit(0);
}

int main(int argc,char *argv[])
{
        int i=0;
        pthread_t pid;
        char *szP=NULL;
        while(true){
                i++;
                pthread_create(&pid,NULL,testthread,&i);
                printf("ok%d,pid=%d\n",i,pid);
                sleep(5);
        }
}
运行测试发现,每次线程创建,都会使内存使用攀升10M(在短信网关中,一个新的socket连接会引起两个线程的创建,而每次内存攀升的量刚好是20M)。
看 来问题已经非常明显,pthread_create存在问题。那么是环境问题还是使用方法上的问题呢?通过仔细阅读man手册,发现pthread一族函 数中有一个叫做pthread_detach的函数,其作用是将资源控制所有权交给子线程(put a running thread in the detached state)。该函数应当由父线程调用。
以往我们写程序的时候,总是在pthread_create之后就万事大吉了,事实上 无论是win下还是*nix下,创建线程都有很多细节问题需要注意。这里面有一点需要说明,并不是pthread_create必须和 pthread_detach结对出现,怎样使用pthread_detach和资源所有权的使用策略相关。一个简单的做法就是通过 pthread_detach将资源所有权交给被创建的线程,这样,一旦该线程退出,pthread_create为其所分配的资源将得到有效释放。


问题的解决:
简 单的解决办法,在所有的pthread_create之后加入了thread_detach。捎带手,还把所有win下的CreateThread所返回 的HANDLE给Close了(免得每次在任务管理器里看到我写的程序都使用了n多句柄)。至于在其他系统上并未出现此问题,可能确实和系统的环境配置有 关,但是并不是说可以依赖环境配置去解决这个问题。因为问题的根本在于pthread_create的用法上。

事后的反思:
从 解决问题的过程上看,此次对问题的解决并没有什么很复杂的过程。和小飞鱼不同的是,小飞鱼所采用的办法是一步步隔离问题,去掉无关项,将问题一步步简化。 而我所采取的是将现实的问题一步步加入到测试环境中,使问题逐渐复杂化。前一种方法在较大的工程中非常有效,而后一种方法在问题的快速解决上有一定优势。 两者的共同点就是:“矢志不渝的进行错误隔离,观察细节引起的差异”。
从问题产生的根源上看,这次的问题不能不说反映了我们开发过程、开发习惯的 一些问题。由于项目紧张,我们可能会在一两天之内就学“一门”新技术,然后把它应用到工程中。可是我们这种“学习”往往为后面的工程带来了很多隐患。另 外,对于我这次的问题来讲,我并不是因为没有时间去学,而是没有去学。主要是看问题只看到能够快速见效的一层,而不去关注那些深层次的问题。这其实是一种 潜意识里的急功近利的思想在作祟。
阅读(1533) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~