Spring导致内存溢出问题
各位看官,我先描述下问题背景:我的应用运行了两年多,期间内存溢出每个星期2次左右,内存溢出后内存又恢复正常,内存溢出不影响 正常使用,内存溢出不宕机,java进程也不变,Tomcat没有重启。
因为不影响使用,也就一直没有管,但是近期发现CPU使用率特别高,不管都不行了。
排查方法:http://www.blogjava.net/hankchen/archive/2012/08/09/377735.html
很好用,定位了问题代码也:
public String getActionName(HttpServletRequest request) {
String _actionName = null;
if ( null != request && null != this.methodNameResolver ) {
try {
_actionName = this.methodNameResolver.getHandlerMethodName(request);
} catch (NoSuchRequestHandlingMethodException e) {
logger.error("获取请求方法名称时失败!", e);
}
}
return _actionName;
}
问题出在第5行代码,查看Spring源码发现,是这句代码:
String servletPath = (String) request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE);
我测试了下,发现从request.getAttribute中取数据就会特别慢,CPU就高,然后我写了测试代码
int count = 0;
Enumeration em = request.getAttributeNames();
while(em.hasMoreElements()){
count++;
String name = em.nextElement().toString();
logger.info("name:"+name+",value:"+request.getAttribute(name).toString());
System.out.println("name:"+name+",value:"+request.getAttribute(name).toString());
}
if(count>20){
logger.info("====================================================count:"+count+",URI:"+uri);
}
结果第3行一直占用CPU,我纠结了,什么情况?
以上几段代码描述的是问题一,CPU占用高。
我换了个写法,暂时绕开了这个问题,但是没有解决,求高人指点,代码如下:
public String getActionName(HttpServletRequest request) {
String _actionName = null;
if(null != request){
String uri = request.getRequestURI();
_actionName = uri.substring(uri.lastIndexOf("/")+1,uri.indexOf(".do"));
}
return _actionName;
}
在这里主要是请教下内存溢出问题,内存溢出是使用ibm memory 易做图yzer工具分析的,分析了五六个内存溢出文件,都是同一个问题,最多的对象是java.lang.Object[293479271] @ 0x708309d20 是个Object数组,数组中存放的都是org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER 或者 org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER。全部是spring request Attribute 中的某个key值,每次溢出都是包含几百万个key(某一个key,重复的)
Object数组中存放的数据见下图:
开始以为是存在内存泄漏,我输出gc日志,查看内存很平稳,只是忽然下就内存溢出了,而且溢出时间没有规律,非高峰期,有时都是凌晨3点、5点,根本很少人访问。用gcviewer工具分析gc日志,截图如下:
最高的那根线就是内存溢出了,之后自己就恢复了。
分析了好几天,也没有思路了,但是总是觉得cpu高和内存溢出是同一个问题导致的,内存溢出时,内存中存放的都是spring request Attribute 中的某个key值,而cpu高,是从request Attribute中取值。难道是Attribute中存放了几百万个key?
麻烦大家帮忙看看,给个思路也好啊,多谢了! --------------------编程问答-------------------- --------------------编程问答-------------------- 1.内存溢出是由于应用程序所使用的内存超过了它所申请或环境分配给它的内存导致的,如果程序写法没问题,可以通过扩大servlet容器所提供的JVM内存来搞定。
2.CPU使用率高是由于应用程序线程过多或一个线程循环次数过快导致的,如果代码中由死循环或无出口递归,那么CPU使用率会达到100%。 --------------------编程问答-------------------- 项目中从来没有遇到过类似问题。貌似不像是楼主公司的代码,是楼主自己的项目吗? --------------------编程问答-------------------- 不知道是不是 Spring 重新加载,对象缓存时候的现象 --------------------编程问答--------------------
详细点不,如何验证? --------------------编程问答--------------------
只是说说我的猜测,先说 spring 的伪代码
创建类实例 对象=反射代码
缓存加入(cache)-对象
java 垃圾回收 cache
重新反射各个对象
个人觉得可以查查配置文件,比如延迟加载(每个类),或者代码中有没有手动的 context 加载
补充:Java , Java EE