本文所讲的是关于通过Java程序来找出内存溢出的原因的研究。
AD:
我曾经在刚入行的时候做过一个小的swing程序,用到了java SE,swing,Thread等东东,当初经验少也没有做过严格的性能测试,布到生产环境用了一段时间后发现那个小程序有时候会抛java.lang.OutofMemoryError异常,就是java的内存溢出。当时也上网查了不少资料,试过一些办法,代码也稍微做了些优化,但是有一个问题我始终是找不到解决的方案 - 不知为什么子窗体关闭后java的垃圾回收机制无法回收其资源,因为这个Java程序可能要经常开关一些子窗体,那么这些子窗体关闭后无法释放资源就造成了Java程序OutOfMemoryError的潜在的隐患!
最近无意间在网上看到了一个监控java程序内存使用的工具 - JProbe,马上回想起那个有关内存溢出的难题,于是我就下载了JProbe8.0.0希望从分析内存入手找到我要的答案。软件下载安装后,在安装目录里详尽的用户指南(懂点软件和英语的人很快就能上手),主要是两个步骤:
1.用JProbe Config工具根据提示生成J2SE或者J2EE程序的控制脚本(一个.jpl文件和一个.bat文件),在命令行里进入.bat文件所在的目录,然后执行该批处理让要监控的java程序跑起来
2.运行JProbe Console工具,点击“Attach to Session...”按钮,弹出java程序的内存实时监控图表“Runtime Summary”,我们主要是看“Data”卡片里的内容(注意:第一次使用该软件可能会遇到一些小问题:比如发布为jar包的程序如果运行时会去读配置文件,从控制脚本启动的话,可能会发生配置文件找不到的异常,解决办法是:不要打jar包,直接就用文件夹发布;还有可能因为一些杀毒软件的网络防火墙导致JProbe无法连接到控制脚本的session,造成监控图表打不开,解决办法是:取消防火墙对于JProbe访问网络的限制)
实时监控图表“Runtime Summary”如下图所示:
可以设置要监视的包或者类,然后点击“Refresh Runtime Data”按钮刷新这些对象占用内存的情况,当你觉得某个类比较可疑的话,你可以在不断的使用程序的过程中监视它的生命周期,看看它是否像预期的那样在结束了生命周期后占用的内存就被释放。众所周知:java的内存回收是自动进行的,无需程序员干预,我们称其为垃圾回收,这个垃圾回收可能是不定期的,就是当程序占用内存资源比较少的情况下可能jvm的垃圾回收频率就比较低;反之,java程序消耗内存资源比较多的情况下,垃圾回收的频率和力度就比较高,这种垃圾回收的不确定性很可能会影响我们的判断,但我们可以点击JProbe监控界面右上方的“Request
a Garbage Collection”(像一个垃圾桶的图标)按钮来向jvm发出垃圾回收的请求,等几秒后再去点击“Refresh Runtime Data”,这个时候如果那个预期应该已经销毁的对象的类名还是没有从监控界面下方的class列中消失或者其对象数量没有减少的话(请多试几次,中间可以夹杂些其他增加程序内存使用的操作以确保jvm确实执行了垃圾回收),那恭喜你!90%的可能性你已经找到了程序的某个缺陷
这个查找元凶的过程可能是相当耗时的,是对程序员的耐心的挑战。我熬了一下午一晚上,功夫不负有心人,基本上把我那个小程序的所有内存溢出的漏洞都找到并补上了。事实告诉我之前那个子窗体关闭后资源无法释放的根本原因是:子窗体虽然调用了dispose()方法,但是子窗体对象的引用一直都在:或者是被静态HashMap引用、或者是它的内部子线程类没有释放、或者是它的某个事件监听类没有释放(借用JProbe的火眼金睛一检验,发现问题真是一大堆啊!),so.我们要彻底释放某个对象占用资源的关键在于找到并释放所有对它的引用!
下面是我解决具体问题的一些经验:
程序中造成内存溢出可能性最大的是HashMap,Hashtable等等集合类,尤其是静态的,更是要慎之又慎!!!它们引用的对象可能你感觉已经销毁了,其实很可能你忘记remove键值,而如果这些集合对象还是静态的挂在其他类里面,那么这个引用可能一直都在,借用JProbe测试一下,结果往往出人意料,解决办法:彻底删除键,remove、clear,如果允许最好把集合对象设为null
对于不再使用的线程对象,如果要彻底杀了它,很多书上都推荐用join方法,我之前也是这样做的,但后来借助JProbe工具我吃惊的发现这样做很可能要杀的线程仍旧好好的活在你日益增大的内存里,很可能调用了线程的sleep方法后用join方法就会有点问题,解决办法:在join方法前再加一句执行interrupt方法,不过这个时候可能会有新的问题:执行interrupt方法后你的线程类会抛InterruptedException,上有政策下有对策,加一个开关变量做判断就能完美解决,可参考下面的代码:
Java代码:
-
-
classNewThreadimplementsRunnable{
- Threadt;
- NewThread(){
-
t=newThread(this,path);
- t.start();
- }
-
publicvoidrun(){
-
try{
-
while(isThreadAlive){
- startMonitor();
-
Thread.sleep(Long.parseLong(controlList.get(controlList.size()-1).toString()));
- }
-
}catch(InterruptedExceptione){
-
if(!ifForceInterruptThread){
- stopThread(logThread);
-
Stringerror="InterruptedException!!!"+path+":Interrupted,线程异常终止!程序已试图重启该线程!!";
- System.err.println(error);
- LogService.writeLog(error);
- createLogThread();
- }
- }
- }
- }
-
-
publicvoidcreateLogThread(){
-
ifForceInterruptThread=false;
-
logThread=newNewThread();
- }
-
-
privatevoidstopThread(NewThreadthread){
-
try{
-
thread.t.join(100);
-
}catch(InterruptedExceptionex){
-
System.out.println("线程终止异常!!!");
-
}finally{
-
thread=null;
- }
- }
-
-
-
-
publicvoidstopThread(){
-
try{
-
ifForceInterruptThread=true;
-
isThreadAlive=false;
- logThread.t.interrupt();
-
logThread.t.join(50);
-
}catch(InterruptedExceptionex){
-
System.out.println("线程终止异常!!!");
-
}finally{
-
this.controlList=null;
-
this.keyList=null;
-
logThread=null;
- }
- }
对于继承JFrame的窗体类,我们要注意在初始化方法中加入:this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); ,并且注意和其关联的事件监听类一律写成窗体类的内部类,这样窗体dispose()的时候,这些内部类也一并销毁,就不会再有什么莫名其妙的引用了。
分享到:
相关推荐
JAVA内存溢出问题总结
完美解决java读取excel内存溢出问题,希望可以帮到大家
JAVA内存溢出详解.docJAVA内存溢出详解.docJAVA内存溢出详解.docJAVA内存溢出详解.docJAVA内存溢出详解.docJAVA内存溢出详解.docJAVA内存溢出详解.docJAVA内存溢出详解.docJAVA内存溢出详解.docJAVA内存溢出详解.doc
java解决大批量数据导出Excel产生内存溢出的方案
kettle内存溢出(Java heap space)以及解决方法
java内存泄露、溢出检查方法和工具。 步骤: 1,使用linux命令生存堆栈文件 2,用MemoryAnalyzer.exe工具打开 3,根据工具生成的饼状图可以清晰的找出内存泄漏源
Java中OutOfMemoryError(内存溢出)的三种情况及解决办法
软件开发 数据库 内存泄露 内存溢出
内存溢出配置,内存溢出配置内存溢出配置内存溢出配置
jboss 内存溢出 优化 jboss 内存溢出 优化
【Java面试题】Java内存溢出
Java内存溢出解决办法 加大Tomcat使用Jvm内存(转载) 注重版权 Caused by: java lang OutOfMemoryError: Java heap space 错误原因及解决方法
Java内存溢出解决办法,很普遍的问题,希望能有所帮助。
解决Java程序内存溢出的几种办法和处理问题的一些经验
java 使用 poi 解析导入大数据量(几万数据量+)时,报出OOM。这是使用POI 第二种处理方法,解决大数据量导入内存溢出问题,并提升效率
ListView优化及加载图片时内存溢出
tomcat内存溢出处理方法适用于java,开发工具myeclipse或eclipse
OOM全称”Out Of Memory”,即内存溢出。 内存溢出已经是软件开发历史上存在了近40年的“老大难”问题。在操作系统上运行各种软件时,软件所需申请的内存远远超出了物理内存所承受的大小,就叫内存溢出。 内存溢出...
程序运行要用到的内存大于虚拟机能提供的最大内存就发生内存溢出了, 内存溢出的问题要看业务和系统大小而定,对于某些系统可能内存溢出不常见,但某些系统还是很常见的解决的方法
该文档详细描述了,内存溢出各种问题和解决方案,适合学习!