一、问题产生
    项目采用Tomcat6.0为服务器,数据库为mysql5.1,数据库持久层为hibernate3.0,以springMVC3.0为框架,项目开发完成后,上线前夕进行稳定性拷机,测试数据为插入4条/S,更新4条/S,访问300次/S,前期运行速度顺畅,三天后就开始运行缓慢,访问量达到1500W次后以抛出Java heap space结束.
二、问题分析
    1.前期分析为连接池内存溢出,期间优化了连接池参数,调整了tomcat线程参数,替换数据库连接池,问题依旧
    2.看来问题不是简单的参数配置,需要进行一点深入的研究分析了,在和同事研究了一些资料后,对JAVA的垃圾收集机制有了一定的了解,JVM的内存模型分为新生代和老生代,JDK本身提供了一个监视工具jconsole.exe,进入bin文件夹打开后,选择连接--tomcat--内存,可以开始监视JVM内存回收情况,通过一段时间的监视后,发现了老生代的内存回收存在异常.

从上图可以看出,每次回收的内存都比上一次少,可以判断老生代的内存发生了泄露.
    3.虽然知道了存在内存泄露,但是无法判断是哪里发生了泄露,为此我们需要把堆(dump)导出来进行分析,JDK也提供了导出工具jvisualvm.exe,启动后右键点击线程--堆Dump,可以导出Dump文件.
    4.使用MAT(MemoryAnalyzer)分析Dump文件,该工具的下载地址为:http://www.eclipse.org/mat,可以下载离线版,也可以集成到eclipse,使用很方便.打开该工具导入Dump文件,稍等一会,就可以得出MAT提供的分析报告:

MAT指出了该Dump中一个HashMap的实例发生了内存泄露,占用了JVM819M的内存,继续点击Details可以得到更详细的信息


这个detail比较详细的指出了问题所在,一个叫viewCache的hashMap实例占用共859M内存,虽然每个实例只有几百字节,但是一共产生了134W个实例.
    5.分析出这个问题点,接下去就是排查代码问题了,排查代码得知该项目使用springMVC,其中viewCache是spring中使用的一个视图缓存,在项目中如一个处理视图跳转的代码:
LinkedList list = this.getPathParam(mvValue);
    for (int i = 0; i < list.size(); i++) {
     String paramName = (String) list.get(i);
     String paramValue = null;
     paramValue = RequestUtils.getParamString(map, paramName);
     paramValue = paramValue == null ? "" : paramValue;
     mvValue = StringUtils.replace(mvValue, "#" + paramName+"#", paramValue);
   }
    return new ModelAndView(mvValue); 
由于paramValue每次都是动态生成的uuid,造成了每次的mvvalue都不同,这样每次都会生成一个不一样的视图,这样的视图累积到100多W个的时候,终于把tomcat撑暴了.百度了一下,果然也已经有人注意到了这个问题:http://jackyrong.iteye.com/blog/1744342.
    6.知道了问题所在后,就可以修改代码了,我们需要将ModelAndView的视图名称固定,动态参数可以通过ModelAndView提供的addObject方法传入,修改后的代码如下:
    ModelAndView mv=new ModelAndView(mvValue);
    LinkedList list = this.getPathParam(mvValue);
    for (int i = 0; i < list.size(); i++) {
     String paramName = (String) list.get(i);
     String paramValue = null;
     paramValue = RequestUtils.getParamString(map, paramName);
     paramValue = paramValue == null ? "" : paramValue;
     mv.addObject("id", ",'"+paramValue+"'");
    }
    return mv;
     7. 代码commit SVN,发布拷机,观察内存回收情况
 
(为了更快模拟环境采用1000次/S插入数据和1000次/S读取数据,所以GC会比较频繁)
可以看出老生代内存得到有效回收,内存泄露的问题得到解决

JAVA简单内存泄露分析及解决的更多相关文章

  1. 记一次Java的内存泄露分析

    当前环境 jdk == 1.8 httpasyncclient == 4.1.3 代码地址 git 地址:https://github.com/jasonGeng88/java-network-pro ...

  2. JAVA内存泄露分析及解决

    一,问题产生     项目采用Tomcat6.0为服务器,数据库为mysql5.1,数据库持久层为hibernate3.0,以springMVC3.0为框架,项目开发完成后,上线前夕进行稳定性拷机,测 ...

  3. Android handler 内存泄露分析及解决方法

    1. 什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引 ...

  4. java中内存泄露有几种?如何分析泄露原因

    一.Java内存回收机制 不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址.Java中对象是采用new或者反射的方法创建的,这些对象的创建都是在堆(Hea ...

  5. .Net内存泄露原因及解决办法

    .Net内存泄露原因及解决办法 1.    什么是.Net内存泄露 (1).NET 应用程序中的内存 您大概已经知道,.NET 应用程序中要使用多种类型的内存,包括:堆栈.非托管堆和托管堆.这里我们需 ...

  6. 【转】.. Android应用内存泄露分析、改善经验总结

    原文网址:http://wetest.qq.com/lab/view/107.html?from=ads_test2_qqtips&sessionUserType=BFT.PARAMS.194 ...

  7. Android Studio 使用Memory Monitor进行内存泄露分析

    在使用Android Studio进行内存泄露分析之前,我们先回顾一下Java相关的内存管理机制,然后再讲述一下内存分析工具如何使用. 一.Java内存管理机制 1. Java内存分配策略 Java ...

  8. java造成内存泄露原因

    一.Java内存回收机制  不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址.Java中对象是采用new或者反射的方法创建的,这些对象的创建都是在堆(He ...

  9. 关于内存泄露分析插件 MAT 的用法

    关于内存泄露分析插件 MAT 的用法,建议大家有时间看一下,下面的文章 http://www.blogjava.net/rosen/archive/2010/05/21/321575.html htt ...

随机推荐

  1. 【html5】html5 本地存储

    最近一直在学习 html5,为了后期的移动项目进行知识储备.html5 相对于 html4 新增加了一些有趣的标签.属性和方法,今天主要介绍下 html5 的本地存储. 在客户端存储数据 html5 ...

  2. jsp 引用css/js文件返回html网页问题

    我的问题: 我直接在web.xml中匹配了 “/” ,以为能默认使用 “localhost:8080/news/” 这种方式,直接进入首页. 但是这样会匹配所有url 因此请求的 ***.js/*** ...

  3. sourcetree向github推送代码提示密码错误

    明明用户名和密码都是正确,sourceTree却在推送代码的时候提示无效的用户名或密码. 1.设置 2.选中并编辑 3.如果你本来选择的就是 GitHub,或者选择完以后还是不行的话,在 URL / ...

  4. mongoimport 导入数据

    最后 利用mongodb自带的mongoimport工具可以上传csv文件 命令如下 mongoimport -h localhost --port 27017 -d test222 -c c21 - ...

  5. Hulu面试题

    1.给定一个N位数,例如12345,从里面去掉k个数字,得到一个N-k位的数,例如去掉2,4,得到135,去掉1,5,得到234.设计算法,求出所有得到的N-k位数里面最小的那一个? 解决方案一:(1 ...

  6. 微信小程序——picker通过value返回你想获取的值

    关于微信小程序中的picker使用方法可以访问:picker-小程序 从它的官方文档中,可以看出它返回的value值是它range的下标: 在项目中,我们大多数时候传的值并不是需要这个下标,而是其他的 ...

  7. C#中二进制和流之间的各种相互转换

    一. 二进制转换成图片间的转换 1 2 3 4 5 MemoryStream ms = new MemoryStream(bytes); ms.Position = 0; Image img = Im ...

  8. 关于sentinel LDK加密war包实现应用加密的使用方法

    经过一周多时间的研究,终于对sentinel产品的使用有个基本的掌握.其中走了不少的弯路,特此记录一下,以备后面回顾. 开发前的用料准备: windows 10 x64位, tomcat7 x64bi ...

  9. ADT安装

    Eclipse安装ADT很简单,直接把下载好的ADT文件解压,覆盖到eclipse目录下的features和plugins目录即可, MyEclipse配置就稍微麻烦了点,我刚开始配置了好几次都不成功 ...

  10. SpringMVC系列(十)<mvc:default-servlet-handler/>(处理静态资源)和<mvc:annotation-driven />

    一.<mvc:default-servlet-handler/>处理静态资源 若将 DispatcherServlet 请求映射配置为 /,则 Spring MVC 将捕获WEB 容器的所 ...