Java_ClassLoader内存溢出-从tomcat的reload说起
原文链接:http://nius.me/classloader-memory-leak/
对于j2ee项目,一直使用eclipse的wtp,每次修改代码后,可以自动热部署。简单的项目wtp似乎没什么问题,但一旦项目代码稍微多一点,就很容易出现各种莫名其妙掉挂的现象,不得不整个重启tomcat服务器,这个时候就很痛苦了。
于是,我换用了maven的jetty插件,启动一个轻量级的jetty服务器,这下热部署似乎没那么多问题了!但是jetty似乎在热部署几次之后,也仍然会崩溃!这是什么情况!tomcat和jetty到底发生了什么?jetty的崩溃最常看见的异常就是OutOfMemoryException,Perm区的内存占满了。
short version
不要慌!为了节省时间,先上解决方案:classloader-leak-prevention。
- 在maven中添加如下配置:
<dependency>
<groupId>se.jiderhamn</groupId>
<artifactId>classloader-leak-prevention</artifactId>
<version>1.9.3</version>
</dependency>
- 在web.xml__顶部__添加一个listener
<listener>
<listener-class>
se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor
</listener-class>
</listener>
- 去西湖玩一天
long version
看看Perm区到底都是些啥
今天实在忍不了了,上Visual VM,监视一下Perm区的情况。
果然,reload几次之后,Perm的使用量蹭蹭的往上涨。看看Perm区都是啥
怎么这么多char[]呀,好像也看不出什么,还是dump一下吧。中间翻阅了一些博客,觉得应该是class loader的问题。oql查询一下。(这里因为是jetty,所以查询了jetty的WebAppClassLoader,如果使用tomcat或者其他容器,应该有对应的Loader,可以通过Saved Queries->PermGen Analysis->ClassLoader Types看一下有哪些ClassLoader)

上图是刚启动的时候,WebAppClassLoader只有一个实例。经过两次reload,嘿,问题来了。如下图:

居然出现了3个WebAppClassLoader实例,前两个Loader都没有销毁!哟呵呵,gc销不掉,一会就进Perm区了,然后多几次reload,Perm区再大也都撑满了。
发生了什么,gc不靠谱?
首先,我们回忆一下gc的运作过程。通过minor gc,清理eden区(eden generation)的没有被引用的对象,活下来的进入suvivor区,接下来的minor gc会让对象在两个suvivor里面倒腾倒腾,挺过几次的进入old区,这里面进行的就是full gc了,耗时长,如果old区还挺了好几次,就会进入Perm区。Perm里面发生的也是full gc.
一个普通对象,只要没有引用了,就一定会在某一次gc被回收。那么ClassLoader进入了Perm,说明在reload的时候,虽然程序取消了对Classloader的直接引用,但是仍然有其他对象间接的引用了ClassLoader。其实如果单纯的仅仅是ClassLoader一个对象,也就罢了,但是ClassLoader并不是一个普通的对象。
任何一个Java类,都是通过某个ClassLoader加载的。通过这个ClassLoader加载的类的实例,会保存这个类对象的引用,也就是MyClass.class这种。而类对象,会保留这个ClassLoader的引用。反过来,在ClassLoader中,也会保持对这个类对象的引用。(注意区分类对象MyClass.class,不是这个类的实例。好吧如果还是混淆了,我也不知道该怎么说清楚了)。关键在于,ClassLoader和类对象之间是双向引用。
双向引用有什么问题嘛?一般情况下没有问题。因为如果ClassLoader的外界引用,和具体类对象的外界引用都消失了,那么这两个对象都不可达了,都会被gc。但是在一些情况下,类对象可能不仅仅被这个类的实例保存,还可能被其他对象保存!如果这个对象是其他OtherClassLoader加载的呢?那意味着,如果这个对象不回收,那么其引用的类对象不会被回收,于是ClassLoader不会被回收,于是,所有ClassLoader加载的类对象都不会被回收!WebAppClassLoader会加载多少个类?如果你恰好使用的是Spring、Hibernate这种大家伙,嚯嚯。如果对此很感兴趣,这里有一篇写的很详细的:Anatomy of a PermGen Memory Leak
怎么解决
你并不知道什么时候会出现某个外部对象会引用到类对象。所以解决问题的思路是,换一个ClassLoader。一开始的解决方案classloader-leak-prevention就是依赖这个思路的。核心代码如下:
// Switch to system classloader in before we load/call some JRE stuff that will cause
// the current classloader to be available for garbage collection
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader()); try {
java.awt.Toolkit.getDefaultToolkit(); // Will start a Thread
}
catch (Throwable t) {
error(t);
warn("Consider adding -Djava.awt.headless=true to your JVM parameters");
} java.security.Security.getProviders(); java.sql.DriverManager.getDrivers(); // Load initial drivers using system classloader javax.imageio.ImageIO.getCacheDirectory(); // Will call sun.awt.AppContext.getAppContext()
让这一段代码运行在servlet初始化之前,在所有的listener之前。
下面是自己翻阅的一些资料:
英文的资料:http://java.jiderhamn.se/2012/03/04/classloader-leaks-vi-this-means-war-leak-prevention-library/ (在此链接可找到最新的maven地址以及源码地址以及非maven得jar)
Git源码地址:https://github.com/mjiderhamn/classloader-leak-prevention
Java_ClassLoader内存溢出-从tomcat的reload说起的更多相关文章
- 内存溢出之Tomcat内存配置
设置Tomcat启动的初始内存其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4. 可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置 三.实例,以下给 ...
- 大神的---解决tomcat内存溢出问题----tomcat报错:This is very likely to create a memory leak问题解决
tomcat memory leak解决方案 这种问题在开发中经常会碰到的,看看前辈的总结经验 Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一 ...
- JAVA:测试java虚拟机支持的最大内存 Xmx 值?Tomcat 内存溢出?(转)
如下命令,即可测试:不断调整n的值,windows上32位的1.6x为: 1610m java -Xmx1610M -versionjava -Xmx1610m -version 网摘的tomcat内 ...
- Tomcat内存溢出的三种情况及解决办法分析
Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一样的,当然处理方式也不一样. 这里根据平时遇到的情况和相关资料进行一个总结.常见的一般会有下面三种 ...
- myeclipse tomcat内存溢出解决方法
Tomcat直接启动正常,通过myeclipse启动tomcat内存溢出.MyEclipse启动Tomcat无视catalina.bat中设置内存大小的问题.在 tomcat的catalina.bat ...
- Tomcat中JVM内存溢出及合理配置及maxThreads如何配置(转)
来源:http://www.tot.name/html/20150530/20150530102930.htm Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚 ...
- 服务器中配置多个Tomcat及内存溢出配置
1.更改server.xml文件中端口(启动.关闭端口) 2.在startup.bat文件开头加上 SET JAVA_HOME=C:\Program Files (x86)\Java\jdk1.8.0 ...
- Tomcat中JVM内存溢出及合理配置
Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对Java JVM有关内存方面的知识 ...
- tomcat内存溢出处理
tomcat内存溢出设置JAVA_OPTS 答案1设置Tomcat启动的初始内存 其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4.可以利用JVM提供的-Xmn ...
随机推荐
- 深入理解javascript原型和闭包(9)——简述【执行上下文】下
继续上一篇文章(http://www.cnblogs.com/wangfupeng1988/p/3986420.html)的内容. 上一篇我们讲到在全局环境下的代码段中,执行上下文环境中有如何数据: ...
- [Head First设计模式]策略模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- Windows群集安装
一.安装前准备 1.安装dotnet 3.5 框架功能 2.安装starwind,并创建虚拟磁盘http://www.cnblogs.com/chhuang/p/3623305.html 3.使用iS ...
- Alpha版本十天冲刺——Day 5
站立式会议 会前小侃:今天是双11,也是恰逢组内秋鑫同学生日,本组同学祝他双11生日快乐.天气好冷,注意保暖. 会议总结 队员 今天完成 遇到的问题 明天要做 感想 鲍亮 json数据解析学习,完成注 ...
- 双系统Ubuntu分区扩容过程记录
本人电脑上安装了Win10 + Ubuntu 12.04双系统.前段时间因为在Ubuntu上做项目要安装一个比较大的软件,导致Ubuntu根分区的空间不够了.于是,从硬盘又分出来一部分空间,分给Ubu ...
- 上个项目的一些反思 I
最近一直在反思之前的项目,发现了很多问题.比如数据安全... 虽然项目需求是只展示最新的数据,所以几乎没用什么本地存储.除了通讯录和用户的Token. 用户通讯录另表,今天反思下用户的Token的存储 ...
- Ubuntu远程vnc配置
1. 安装xrdp 使用快捷键"Ctrl+Alt+T"打开一个终端窗口,输入"sudo apt-get install xrdp"-->回车-->输 ...
- Java内部类详解
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
- kali2.0中dradis的使用方法
启动脚本位于:/usr/lib/dradis下,再该目录下有一个start.sh文件,执行后,可以在浏览器中输入https://localhost:3004即可打开dradis的web接口 切记前面h ...
- Linux网络管理2---(网络环境查看命令、网络测试命令)
1.网络环境查看命令 ifconfig命令 查看或临时修改网络状态的命令 可以看到IP.子网掩码……信息 关闭和启动网卡 ifdown 网卡设备名(比如: ifdown eth0):禁用该网卡设备 i ...