




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、我做的应用是以Spring为系统的基础框架,mysql为后台数据库.在tomcat上发布后,总是不能进行热部署(reload),多次reload后,就会出OutOfMemory PermGen,为此烦恼了很久,总于下定决心找找根源.经过3天的不懈努力,小有成果,记录下来实际上下面的分析都已经没什么用了,如果你使用tomcat6.0.26及以后的版本,我所说的这些情况都已经被处理了,并且比我处理的还要多很多.可以下载tomcat6.0.26的源代码看看WebappClassLoader类的处理就成了.通过分析工具的分析(用了YourKit,以及JDK1.6/bin下的jps/jmap/jhat)
2、,发现有下面几个方面会造成memory leak.1.SystemClassLoader与WebappClassLoader加载的类相互引用,tomcat reload只是卸载WebappClassloader中的class,SystemClassLoader是不会卸载的(否则其他应用也停止了).但是WebappClassloader加载的类被SystemClassLoader引用的化,WebappClassloader中的相关类就不会被JVM进行垃圾收集ThreadLocal.set(Object),如果这个Object是WebappsClassLoader加载的,使用之后没有做Thread
3、Local.set(null)或者ThreadLocal.remove(),就会产生memory leak.由于ThreadLocal实际上操作的是java.lang.Thread类中的ThreadLocalMap,Thread类是由SystemClassLoder加载的.而这个线程实例(main thread)在tomcat reload的时候不会销毁重建,必然就产生了SystemClassLoder中的类引用WebappsClassLoader的类.DriverManager也是由SystemClassLoder载入的,当初始化某个JDBC驱动的时候,会向DriverManager中注册该
4、驱动,通常是*.driver,例如com.mysql.jdbc.Driver这个Driver是通过class.forName()加载的,通常也是加载到WebappClassLoader.这就出现了两个classLoader中的类的交叉引用.导致memory leak.解决办法:写一个ServletContextListener,在contextDestroyed方法中统一删除当前Thread的ThreadLocalMap中的内容.public class ApplicationCleanListener implements ServletContextListener public void
5、 contextInitialized(ServletContextEvent event) public void contextDestroyed(ServletContextEvent event) /处理ThreadLocal ThreadLocalCleanUtil.clearThreadLocals(); /* * 如果数据故驱动是通过应用服务器(tomcat etc.)中配置的<公用>连接池,这里不需
6、要 否则必须卸载Driver * * 原因: DriverManager是System classloader加载的, Driver是webappclassloader加载的, * driver保存在DriverManager中,在reload过程中,由于system * classloader不会销毁,driverManager就一直保持着对driver的引用, * driver无法卸载,与driver关联的其他类 * ,例如DataSo
7、urce,jdbcTemplate,dao,service.都无法卸载 */ try System.out.println("clean jdbc Driver."); for (Enumeration e = DriverManager.getDrivers(); e .hasMoreElements();) Driver driver = (
8、Driver) e.nextElement(); if (driver.getClass().getClassLoader() = getClass() .getClassLoader() DriverManager.deregisterDriver(driver); catch (Exception e
9、) System.out .println("Exception cleaning up java.sql.DriverManager's driver: " + e.getMessage(); /* 这个类根据*/public class ThreadLocalCleanUtil /* 得到当前线程组中的所有线程 description:* * ret
10、urn*/private static Thread getThreads() ThreadGroup tg = Thread.currentThread().getThreadGroup(); while (tg.getParent() != null) tg = tg.getParent(); int threadCountGuess = tg.activeCount() + 50; Thread threads = new Th
11、readthreadCountGuess; int threadCountActual = tg.enumerate(threads); while (threadCountActual = threadCountGuess) threadCountGuess *= 2; threads = new ThreadthreadCountGuess; threadCountActual = tg.enumerate(threads);
12、0; return threads;public static void clearThreadLocals() ClassLoader classloader = Thread .currentThread() .getContextClassLoader(); Thread threads = getThreads(); try Field thr
13、eadLocalsField = Thread.class .getDeclaredField("threadLocals"); threadLocalsField.setAccessible(true); Field inheritableThreadLocalsField = Thread.class .getDeclaredField("inheritableThrea
14、dLocals"); inheritableThreadLocalsField.setAccessible(true); Class tlmClass = Class .forName("java.lang.ThreadLocal$ThreadLocalMap"); Field tableField = tlmClass.getDeclaredField("table");
15、60; tableField.setAccessible(true); for (int i = 0; i < threads.length; +i) if (threadsi = null) continue; Object threadLocalMap = threadLocalsField.get(threadsi);
16、clearThreadLocalMap(threadLocalMap, tableField, classloader); threadLocalMap = inheritableThreadLocalsField.get(threadsi); clearThreadLocalMap(threadLocalMap, tableField, classloader); catch (Exception e)
17、0; e.printStackTrace(); private static void clearThreadLocalMap(Object map, Field internalTableField, ClassLoader classloader) throws NoSuchMethodException, IllegalAccessException, NoSuchFieldException, InvocationTargetException
18、; if (map != null) Method mapRemove = map.getClass().getDeclaredMethod("remove", new Class ThreadLocal.class ); mapRemove.setAccessible(true); Object table = (Object) internalTableField.get(map);
19、0; int staleEntriesCount = 0; if (table != null) for (int j = 0; j < table.length; +j) if (tablej != null) boolean remove = false; Object
20、key = (Reference) tablej).get(); if (key != null) && (key.getClass().getClassLoader() = classloader) remove = true; System.
21、out.println("clean threadLocal key,class=" + key.getClass().getCanonicalName() + ",value=" + key.toString();
22、60; Field valueField = tablej .getClass() .getDeclaredField("value"); valueField.setAccessible(true); Object value =
23、 valueField.get(tablej); if (value != null) && (value.getClass().getClassLoader() = classloader) remove = true; System.out.
24、println("clean threadLocal value,class=" + value.getClass().getCanonicalName() + ",value=" + value.toString(); &
25、#160; if (remove) if (key = null) +staleEntriesCount; else mapRemove.invoke(map, new Object key );
26、160; if (staleEntriesCount > 0) Method mapRemoveStale = map .getClass()
27、0; .getDeclaredMethod("expungeStaleEntries", new Class0); mapRemoveStale.setAccessible(true); mapRemoveStale.invoke(map, new Object0); 2.对于使用mysql JDBC驱动的:mysql JDBC驱动会启动一个Timer Thread,这个
28、线程在reload的时候也是无法自动销毁.因此,需要强制结束这个timer可以在 上面的ApplicationCleanListener中加入如下代码: try Class ConnectionImplClass = Thread .currentThread() .getContextClassLoader() .loadClass("com.
29、mysql.jdbc.ConnectionImpl"); if (ConnectionImplClass != null && ConnectionImplClass.getClassLoader() = getClass() .getClassLoader() System.out.println("clean mysql timer."); Field f = ConnectionImplClass.getDeclaredField("cancelTimer");
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年湖北省初中毕业生学业水平考试历史综合试卷(二)教师版
- 西安明德理工学院《联络口译》2023-2024学年第一学期期末试卷
- 汕头市重点中学2024-2025学年高三摸底调研测试英语试题含解析
- 郑州大学《民航英语听说》2023-2024学年第二学期期末试卷
- 云南省绿春县一中2024-2025学年高三化学试题综合练习(四)含附加题含解析
- 红河职业技术学院《书写技能(硬笔字)》2023-2024学年第一学期期末试卷
- 新疆石河子职业技术学院《企业管理学》2023-2024学年第二学期期末试卷
- 郑州工业安全职业学院《数字影像技术》2023-2024学年第二学期期末试卷
- 平顶山市鲁山县2024-2025学年数学四年级第二学期期末质量跟踪监视试题含解析
- 娄底市新化县2025年五下数学期末教学质量检测试题含答案
- 教科版小学科学六年级下册单元练习试题及答案(全册)
- 李大钊简介完
- 中考英语阅读理解:图表类(附参考答案)
- 农作物病虫害防治服务投标方案(技术标)
- 扫地机器人创业项目计划书
- 【班级管理表格】学生检讨反思承诺书
- GSV2.0反恐安全管理手册
- 应用文写作说课稿 终稿
- 单位车辆领取免检标志委托书范本
- 行政公文写作-决定(应用文写作课件)
- 机械设计说明书-激光熔覆送粉器设计
评论
0/150
提交评论