一次tuxedo应用内存问题排查报告
××系统在生产环境运行过程中发现应用服务器的内存不断在减少,某些调用频繁的程序现象尤其明显。估计内存存在泄漏问题(本系统服务器使用AIX,中间件使用tuxedo8.1)
选择一个调用频繁的server进行测试
选择s_PubCheckSerial(校验员工序列号)进行测试,该服务在每个service中都要调用到。
测试一:
用在系统实际运行的s_PubCheckSerial在测试机上单独进行测试。写一个client端程序,在程序中直接调用CheckSerial函数(该函数中有调用检验序列号service).
Server初启动时的内存大小:1.7M
调用10000次后内存大小:5.2M
测试二:
采用测试一中一样的client端程序,将service中所有调用到TOCIQuery类的地方全部屏蔽。
Server初启动时的内存大小:1.7M
调用10000次后内存大小:5.2M
说明内存泄漏问题不是由该类引起。
测试三:
采用测试一中一样的client端程序,将service中所有调用到TOCIQuery类的地方全部屏蔽。将service中的用到wwfput函数的地方全部关闭。
Server初启动时的内存大小:1.7M
调用10000次后内存大小:5.2M
说明内存泄漏与wwfput无关。
测试四:
进行到以上三次测试时service本身已没有实际功能的语句,只有wwfgets函数,但该函数只是从FML中取数据,不太可能造成内存泄漏。
联想到在实际环境中取得的内存数据,svr_DtSqlServer这个server同样调用频繁,但它的内存好像比较稳定,不会不断的增长(该service的内存增长与查询的数据量有关,在查询数据量不大的情况下,内存会稳定在一个达到最大值)。比较这两个server的写法,svr_DtSqlServer采用传统的写法,在处理正常的情况下在try数据块中执行wwreturn,而s_PubCheckSerial则采用抛出异常的方式即不论正常执行还是执行异常都是在catch数据块执行wwreturn。因为wwreturn内部执行了long jump,在这之前定义的类不会自动调用类的析构,会不会在对抛出的异常空间的释放上也有同样的问题。
把catch中的wwreturn语句提到catch之后执行
Server初启动时的内存大小:1.7M
调用10000次后内存大小:1.8M
运行10000次后内存稳定在1.8M,这属于正常情况。
分析,估计C++编译器要在退出catch块之后才释放抛出的异常所占用的内存空间,但由于程序在catch中执行了wwreturn,而该函数内部执行了longjump操作,可能问题是该操作造成抛出的异常空间无法释放造成的。
本系统的service采用的写法都是在出现执行异常时在catch块中直接wwreturn的写法,不同的是,一般service中catch的异常都采用引用的方式,而该测试service采用传入变量的方式。因此还要对其他service进行一个测试验证是否出现同样的情况。
附:修改的程序段
修改前代码:
try
{
……
}
catch(int nCode)
{
wwfput(&sendBuf, DEAL_ERROR_ERR_ID, 0 , stErr.ErrId);
wwfput(&sendBuf, REC_LOG_ERR_INFO, 0 , stErr.Err);
if (nCode != 0)
{
if (qry != NULL)
{
delete qry;
qry = NULL;
}
nFlag = -1;
userlog("step before return TPFAIL tperrno:%d",tperrno);
wwreturn(TPFAIL,0,(char *)sendBuf,0L);
}
else
{
if (qry != NULL)
{
delete qry;
qry = NULL;
}
nFlag = 0;
userlog("step before return SUCCESS tperrno:%d",tperrno);
wwreturn(TPSUCCESS,0,(char *)sendBuf,0L);
}//end else
}//end catch int nCode
修改后:
{
try
{
……..
}
catch(int nCode)
{
wwfput(&sendBuf, DEAL_ERROR_ERR_ID, 0 , stErr.ErrId);
wwfput(&sendBuf, REC_LOG_ERR_INFO, 0 , stErr.Err);
if (nCode != 0)
{
if (qry != NULL)
{
delete qry;
qry = NULL;
}
nFlag = -1;
userlog("step before return TPFAIL tperrno:%d",tperrno);
// wwreturn(TPFAIL,0,(char *)sendBuf,0L);
}
else
{
if (qry != NULL)
{
delete qry;
qry = NULL;
}
nFlag = 0;
userlog("step before return SUCCESS tperrno:%d",tperrno);
// wwreturn(TPSUCCESS,0,(char *)sendBuf,0L);
}//end else
}//end catch int nCode
if(nFlag == 0)
wwreturn(TPSUCCESS,0,(char *)sendBuf,0L);
else
wwreturn(TPFAIL,0,(char *)sendBuf,0L);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
备注一下:ww***的函数是经过简单封装的tuxedo的f***函数。