1. 概述
12585系统最近频繁告警,有时可以自己恢复,有时系统完全挂死重启才能恢复正常业务。
2. 系统环境
操作系统:Linux 64位系统
Weblogic版本:10.3.6
JDK版本:1.6
双机集群环境
3. 问题分析
检查weblogic系统日志,发现有内存溢出错误发生;查看JVM内存设置参数发现当前3个server(管理和两个受管)最小和最大堆内存设置均为9G,没有配置内存溢出参数和GC日志参数,也没有对线程和GC进行优化。为了能够在下次问题出现时生成heapdump文件来分析内存溢出的原因,修改受管server的启动脚本,添加如下JVM参数:
export USER_MEM_ARGS="-Xms4096m -Xmx4096m -XX:MaxPermSize=512m -XX:NewSize=1800m -XX:MaxNewSize=1800m -verbose:gc -Xloggc:/export/home/logs/server1GC.log -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError -Dweblogic.threadpool.MinPoolSize=100 -Dweblogic.threadpool.MaxPoolSize=400"
发现堆内存设置减少后内存溢出频率并没有增加,绝大多数时间堆内存剩余均比较多,偶尔有内存迅速被占满,之后又被回收的情况发生,初步可以判断出是由于某一个类型的操作或者业务对象导致短时间内内存被迅速占满产生内存溢出。
12月16日下午2点40左右出现一次内存溢出,并生产了dump文件,结合内存溢出错误和dump文件发现如下问题:
####<2013-12-16 下午02时40分38秒 CST> <Error> <HTTP> <LNSY-PS-12585-HJ01> <server1> <[ACTIVE] ExecuteThread: '65' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1387176038382> <BEA-101017> <[ServletContext@1268001340[app:ROOT module:ROOT path: spec-version:2.5]] Root cause of ServletException.
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2734)
at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
at java.util.ArrayList.add(ArrayList.java:351)
at com.ln12585.local.service.MessageSender.changeLength(MessageSender.java:649)
at com.ln12585.local.service.MessageSender.sendSms(MessageSender.java:461)
at com.ln12585.local.service.BaseLocal.sendSms(BaseLocal.java:36)
at com.ln12585.service.sms.datamodal.SmsSender.send(SmsSender.java:27)
at com.ln12585.service.SendMes.doPost(SendMes.java:58)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:301)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at com.ln12585.filter.SMSServiceFilter.doFilter(SMSServiceFilter.java:74)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at com.ln12585.filter.ServiceFilter.doFilter(ServiceFilter.java:64)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3730)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3696)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2273)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1490)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
>
分析heapdump文件可以看出95%的堆空间被一个类型的对象占用ArryList对象,配合内存溢出时打出的堆栈将内存溢出点锁定在如下程序代码:
at com.ln12585.local.service.MessageSender.changeLength(MessageSender.java:649)
at com.ln12585.local.service.MessageSender.sendSms(MessageSender.java:461)
at com.ln12585.local.service.BaseLocal.sendSms(BaseLocal.java:36)
应用开发人员查看源代码发现上面的代码确实存在进入无限for循环往ArrayList里放空字符串的bug:
int j = 0;
int tempTotal = temp.length;
for (int i = 0; i < tempTotal; i++) {
if (((String)temp1.get(j)).toString().length() + temp[i].length() < messagesize - 5) {
String t1 = (String)temp1.get(j);
temp1.remove(j);
if (i != tempTotal - 1)
temp1.add(j, t1 + temp[i] + ";\n");
else {
temp1.add(j, t1 + temp[i]);
}
}
else
{
String t2 = (String)temp1.get(j);
temp1.remove(j);
temp1.add(j, t2 + "###");
temp1.add("");
j++;
i--;
}
}
当第一个条件不满足进入else后i先加1然后再减1进入条件判断之后则无限循环下去,每次都执行temp1.add(“”) 往ArrayList里放空字符最后导致内存瞬间被占满。
4. 问题建议
请应用开发人员配合修改程序代码避免上面的bug情况发生,暂时可将循环条件增加对j值的判断避免无限循环,之后再重新调整业务逻辑代码。
数据库连接池调整。起初数据库连接池的最大值设置只有5,日志中也出现了达到数据库连接最大值的信息,之后将最大连接调整为30,发现还是会达到最大值,同时还有连接等待的情况,如下:
最大连接等待25,建议将最大数据库连接由现在的30调整为60继续观察,并建议将连接池高级参数”保留测试连接”选中,保证客户端拿到的连接都真实可用。
该贴被funny编辑于2014-3-5 13:16:51该贴被funny编辑于2014-3-5 13:17:58