我曾l在刚入行的时候做q一个小的swingE序Q用Cjava SEQswingQThread{东东,当初l验也没有做过严格的性能试Q布到生产环境用了一D|间后发现那个程序有时候会抛java.lang.OutofMemoryError异常Q就是java的内存溢出。当时也上网查了不少资料Q试q一些办法,代码也稍微做了些优化Q但是有一个问题我始终是找不到解决的方?- 不知Z么子H体关闭后java的垃圑֛收机制无法回收其资源Q因个JavaE序可能要经常开关一些子H体Q那么这些子H体关闭后无法释放资源就造成了JavaE序OutOfMemoryError的潜在的隐?zhn)Q?/p>
最q无意间在网上看C一个监控javaE序内存使用的工?- JProbeQ马上回惌v那个有关内存溢出的难题,于是我就下蝲了JProbe8.0.0希望从分析内存入手找到我要的{案。Y件下载安装后Q在安装目录里详的用户指南Q懂点Y件和p的h很快p上手Q,主要是两个步骤:
1.用JProbe Config工具Ҏ(gu)提示生成J2SE或者J2EEE序的控制脚本(一?jpl文g和一?bat文gQ,在命令行里进?bat文g所在的目录Q然后执行该批处理让要监控的javaE序跑v?/p>
2.q行JProbe Console工具Q点?#8220;Attach to Session...”按钮Q弹出javaE序的内存实时监控图?#8220;Runtime Summary”Q我们主要是?#8220;Data”卡片里的内容Q注意:W一ơ用该软g可能会遇C些小问题Q比如发布ؓjar包的E序如果q行时会去读配置文gQ从控制脚本启动的话Q可能会发生配置文g找不到的异常Q解军_法是Q不要打jar包,直接q文g夹发布;q有可能因ؓ一些杀毒Y件的|络防火墙导致JProbe无法q接到控制脚本的sessionQ造成监控图表打不开Q解军_法是Q取消防火墙对于JProbe讉K|络的限Ӟ
实时监控图表“Runtime Summary”如下图所C:
可以讄要监视的包或者类Q然后点?#8220;Refresh Runtime Data”按钮hq些对象占用内存的情况,当你觉得某个cL较可疑的话,你可以在不断的用程序的q程中监视它的生命周期,看看它是否像预期的那样在l束了生命周期后占用的内存就被释放。众所周知Qjava的内存回收是自动q行的,无需E序员干预,我们U其为垃圑֛Ӟq个垃圾回收可能是不定期的,是当程序占用内存资源比较少的情况下可能j(lu)vm的垃圑֛攉率就比较低;反之QjavaE序消耗内存资源比较多的情况下Q垃圑֛收的频率和力度就比较高,q种垃圾回收的不定性很可能会媄响我们的判断Q但我们可以点击JProbe监控界面右上方的“Request a Garbage Collection”Q像一个垃圾桶的图标)按钮来向jvm发出垃圾回收的请求,{几U后再去点击“Refresh Runtime Data”Q这个时候如果那个预期应该已l销毁的对象的类名还是没有从监控界面下方的class列中消失或者其对象数量没有减少的话Q请多试几次Q中间可以夹杂些其他增加E序内存使用的操作以保jvm实执行了垃圑֛ӞQ那恭喜你!90%的可能性你已经扑ֈ了程序的某个~陷
q个查找元凶的过E可能是相当耗时的,是对E序员的耐心的挑战。我熬了一下午一晚上Q功夫不负有心hQ基本上把我那个程序的所有内存溢出的漏洞都找到ƈ补上了。事实告诉我之前那个子窗体关闭后资源无法释放的根本原因是Q?span style="color: red">子窗体虽然调用了dispose()Ҏ(gu)Q但是子H体对象的引用一直都在:或者是被静态HashMap引用、或者是它的内部子线E类没有释放、或者是它的某个事g监听cL有释?/span>Q借用JProbe的火眼金睛一验,发现问题真是一大堆啊!Q,so.我们要彻底释放某个对象占用资源的关键在于扑ֈq放所有对它的引用Q?/p>
下面是我解决具体问题的一些经验:
E序中造成内存溢出可能性最大的是HashMapQHashtable{等集合c,其是静态的Q更是要慎之又慎Q!Q?/span>它们引用的对象可能你感觉已经销毁了Q其实很可能你忘记remove键|而如果这些集合对象还是静态的挂在其他c里面,那么q个引用可能一直都在,借用JProbe试一下,l果往往Zh意料Q解军_法:d删除键,remove、clearQ如果允许最好把集合对象设ؓnull
对于不再使用的线E对象,如果要彻底杀了它Q很多书上都推荐用joinҎ(gu)Q我之前也是q样做的Q但后来借助JProbe工具我吃惊的发现q样做很可能要杀的线E仍旧好好的zd你日益增大的内存里,很可能调用了U程的sleepҎ(gu)后用joinҎ(gu)׃有点问题Q解军_法:在joinҎ(gu)前再加一句执行interruptҎ(gu)Q?/span>不过q个时候可能会有新的问题:执行interruptҎ(gu)后你的线E类会抛InterruptedExceptionQ上有政{下有对{,加一个开兛_量做判断p完美解决Q可参考下面的代码Q?/p>
Java代码Q? 对于l承JFrame的窗体类Q我们要注意在初始化Ҏ(gu)中加入:this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); Qƈ且注意和其关联的事g监听cM律写成窗体类的内部类Q这L(fng)体dispose()的时候,q些内部cM一q毁,׃会再有什么莫名其妙的引用? 资料来源:http://developer.51cto.com/art/200906/128944.htm
]]>