如何解决Java内存泄漏

所需积分/C币:39 2015-09-22 16:45:00 335KB PDF
收藏 收藏
举报

如何解决Java内存泄漏
背景 提供了垃圾回收机制,实现了对内存回收的自动管理,大家在廾发程序的时 候不用再像一样手工的去调用函数来释放内存,这很大稈度上简化了稈序开发,提高了 编程效率,但这也是个双刃剑,些开发人员就认为没有内存泄漏问题,开发过程 中不注意对无效对象的释放和管理,在某些情况下不仅会造成系统运行效率低下,也造成了 内存泄漏。 在以往的项目中接连发现内存泄漏,有些相当严重,对系统长期稳定运行造成很大影响。 内存泄漏的表现和诊测手段和不同,所涉及的方面比较多,一直也是应用系统开 发的老大难问题,这里专门把内存泄漏方面的东西整理出米,希望在开发和测试过程 对这个问题高度重视,争取在开发阶段就把问题避免了。 内存回收机制 在中所有对象都是在堆中分配的,对象的创建通常都是采用或者是反 射的方式,但对象释放却没有直接的手段,所以对象的回收都是由虚拟机通过垃圾回 收线程()去完成的。 中对象回收的原则是这个 准确的说是不再被系统运行线程中的各种对象 引用,具体后面会详细介绍。垃圾回收线程怎么知道个对象不再使用需要回收呢?这就需 要垃圾回收线程监控每一个对象的运行状态,包括对象的中请、引用、被引用、赋值等。 为了更好理解的工作原理,我们可以将对象考虑为有向图的顶点,将引用关系考虑 为图的有向边,有向边从引用者指向被引对象。另外,每个线程对象可以作为一个图的起始 顶点,例如大多程序从进程开始执行,那么该图就是以进程顶点开始的一棵根树。 在这个有向图中,根顶点可达的对象都是有效对象,将不回收这些对象。如果某个对象 连通子图与这个根顶点不可达注意,该图为有向图,那么我们认为这个这些对象不再被 引用,可以被回收 以下,我们举一个例子说明如何用有向图表小内存管理。对于程序的每一个时刻,我们 都有一个有向图表示的内存分配情况。以下右图,就是左边程序运行到第行的示意 图 Public static id m ainstringalD Object ol =new Objecto Object o2 Objecto 此行为第6行 0b2 mai进程 该图描述了第6行的内存管理的有向图 O2是第二次申请的对象,此时为可回收对象 前面是一个最简单的例子,只是回收一个没有任何引用对象,但大部分情况下都比这个 复杂得多,往往需要进行复杂的计算来确定一组对象做为整体没有外部引用,而全部可 以释放。我们来看一个典型的程序的内存使用示意图: 第页 有效对象空间 上图中最外面代表整个内存堆,中间灰色的框代表系统运行所需有效对象空间,从垃圾 回收的角度看这里有四类对象 有效对象,在灰色框中的对象,这是系统运行需要的对象,不能被垃圾回收掉。 独立的无效对象,系统不需要再使用,而且没有任何外部引用,这类对象很快就会 被垃圾回收掉。 组无效的对象,从整体看系统凵经不再需要这些对象,不过这些对象问存在相互 依赖,这类对象的回收与垃圾回收线稈算法相关,可能不会立刻回收掉,需要一段 时间计算。 被有些对象引用到的无效对象,这就是我们要解决的内存泄漏的对象 对于程序员来说,基本是透明的,只有几个函数可以访问,常见的是运行 的函数 但是根据语言规范定义,该函数不保证的垃圾收集器定 会执行。不同的实现者可能使用不同的算法管理通常的线程的优先级别较低。 调用的策略也有很多种,有的是內存使用到达一定程度时才开始工作,也有定 时执行的,有的是平缓执行,有的是中断式执行通常来说,程序员不需要关心这 些,除非在一些特定的场合,的执行影响应用程序的性能,例如对于基于的实时系 统,如网络游戏等,用户不希望突然中断应用程序执行而进行垃圾回收,那么我们需要 调整的参数,让能够通过平缓的方式释放内存,例如将垃圾回收分解为一系列的小 步骤执行。 如何检查内存泄漏 内存泄漏有专门的检查上具,我们般采用 公司的 ,当然还有 其他一些常见的工具如 和 ,下面以 为例介绍。 程序的安装 去官方网站下载 试用版安装文件、并安装 如何配置 步骤一:添加一个虚拟机 ”对话框,选中“ ”页,选择“ 第页 在弹出的对话框中将指定的加入,并将其设置为 步骤新建一个运行设置:“”一一)“ 步骤三:选中“ 页 选中 选择可执行的测试程序; ”选择被测对象所在的工作口录 ”中选中“ 在 ”中设置系统运行需要的最大内存值,缺省是一般 不能满足要求需要自行设置,如果有其他参数也可以在这里设置; 设置 ”,在 ”对话框中,设置与被测对象路径有关的 单击按钮” ”就开始运行了。 运行时如图所示: Edition F: Jboss\jbe Tools (ptim zeit Info i密区魔图国网 Heap 798 169456b 4356b java Ltil Tree MapsErtry i3 Ltil Hash Map$三rtr 384b orc,apacheJog+, rcsi nps java rio. HeapCnarBuffer 3 11 ario.HeapBvteBufer 376b 1120b+1120b Not'3d1lEx,epion 331 132b HAlil.LinkelLisIsEnlry 6b+138b sEcurit. oriileye dIction Except on aLlier.Alribules 圃乒画回‖恩国頭。氫如。丝未。1到⑨汪」⑨,國c」民多钞溪紧照回17 一般最常用的就是上面红色标识的个按钮,从左到右: ”垃圾回收按钮,强制执行 显示整个内存堆分配状态按钮,点击后就出现上面的画面 显示对象分配比例,和产生对象实例的调用栈 显示对象引用关系和产生对象实例的调用 栈 给当前的对象实例打标签。 对于“ ”,专门提一下,如果系统运行期产生了很多临时对象, 如特别多,怎么才能确定这些对象都是由谁产生的呢?就可以通过“ 第页 查看到这些对象是产生的堆栈,有时候的对象是一个地方生成的,分析这 个点减少临时对象的产生,进而可以实现对系统的优化。 如何利用 检查内存泄漏 在进行内存泄漏测试前,我们首先要确定待测试的流程,就是怀疑存在内存泄漏的地方, 例如,客户端通常在打开一个对话框或者分视图,关闭后有可能会有内存汁漏,这里打开关 闭个对话框就是·个测试流程。我们把个测试流程分为三个阶段 阶段,功能运行前,还没有调用具体的功能,这时我们需要等系统运行稳定后打一个 标签: se Edition-F:Jboss, jbDss-324:jbo5s324ais+ 卜 le EdIt Ptocram I Ⅲ到图圈赠图腰国害回罡斗 HC-p Mrtyal maco rc runn >Instance count Dft. Size Size di. 17:k aLtil. HashMaoBEntry 17542[Cb+4Cb Hea pchareliffer ava rio. le a pDte Duffer N扌lgr ava ltil Linke dList Cntr 柜1b27图口 1714b+14Eb Disable We cullet, Lr 回画回偏‖鸟如匈。元。出9國注,@h塑取」國度多必单菜国10 如图中红色标识的按钮,点击后下面这一列就变为 代表当前没有差异。 阶段,运行系统功能。 阶段,功能运行后,返回到阶段的状态,这时系统应该和阶段处于相同的状态。 连续点击三次垃圾回收按钮(扫帚图标),避免有对象没有及时回收,然后观察列总对 象实例总的内存大小变化情况,这里表格中各列可以单击表头排序。 系统稳定后存在对象增长,如果这个类增加∫一个实例,当然仅仅增加一个实例往往不 能说明问题,因为我们系统巾有很多地方采用单子模式,有可能造成一个对象增加,我们重 复前面三个步骤,可以看到每次操作都会增加个实例,阶段和阶段都处于同样的状态, 按道理说对象数日应该是相同的,如果存在对象持续增长就说明有内存泄漏。 最下面一栏有一个功能,可以在这里设置按包路径进行过滤,这样能 集中关注某些类,便」定位,但在有些情况下可能叁遗漏掉一些其他类,所以最好在有针对 性的观察后把过滤条件去掉,看看其他对象有没有增长 进·步分析: 第页 找到没有释放的对象,后面一个很重要的工作就是找出什么原因造成对象没有被垃圾回 收掉,引起内存泄漏的,点击下图中红色的“ 按钮可以查 看到这个对象引用的详细信息: Optimizeit Profiler 5. 5 Enterprise Edition- F:\Jboss\boss 3.2.\ibcss324,ois* L File Edit Program Tools Optimizeit Info Ⅲ国豆国 Instances of co mzte ums zxpcs wf pm. statistic query quen chartcondition Dialon Virtual machine rnnning Alloc onder Descision 1065]660Tmeout while calling to String on instance of class com de ums zxpcs wsf pm statist c, quer Q Jerchartco niter Disagx 卩00486-90hc| to string on instance of cla3mWm(swpm威 stc query Q Jerychartc0r词d0g IRe dueed referente graph ·Tmc冲h:mg1s的的tncs:0m型P: y COncha1 hditionDialog= e QueryC hartConditionnigor 1 0Da1e4Ba (gxnecing cescnptian a. querl anager of 100a21faf expecting des riot cn) parent of100a21ihd iep target cf 10Ca3a839 eXpecting de cn) JNI global reterence emment cr 1009EeBfaiexpectinu 日· eleeniDalayf 100cs97↑ ferpectrigdescrptor Sat=vaa|eoCa3 3 sunaMtwondo能Ynd0wP色r rent c1100- 28f 3 (expect nd description) ths0100a2933(出量击一 thi ss0 or100a29353(experiing description thisso of 100a29372(expe :ling description) 国sU1s( EyDe:Hng description LAllccaled at (ExpEcting location.> (EXpEcting location.) Exr∈ cting location 上图中分为三个区域,上方区域列出了当前堆中所有的对象实例,中间是选中实例的具 体引用关系表,从这里我们可以看到为什么这个实例不能被垃圾回收,下方的区域显示出了 这个实例的创建堆栈。通过这个图结合代码我们可以很容易的找到内存泄漏存在的地方。 上图中 对象有很多地方是被内部类引用的,这中引用属于内 部引用不会影响这个对象的垃圾回收,这里真正影响回收的是被 这个类的内部静态变量引用了,在窗∏关闭的吋候没有调用窗∏的 方法。查看 方法的说明,可以看出这是用于释放窗口资源的方法,如果不调用窗口资源是不 会释放的。 常见内存泄漏实例 4.1简单的例子 用一个循坏中请 对象,并将所中请的对象放入一个 中,如果仅仅释放引 用本身,那么仍然引用该对象,所以这个对象对来说是不可回收的。因此,如果 对象加入到 后,还必须从 中删除,调用 的 方法,当然如果这个 不使用了,直接将 对象设置为,所以对象都会被释放了。 第页 此时,所有的 对象都没有被释放,因为变量引用这些对象 42客户端内存泄漏 对话框在需要释放时没有采用 ()方法向 注销,造成资源的不可回 收例 反 正例 反例: 资源释放时只是释放了对话框中组件试用的侦听器,没有释放对话框本身 正例: 对话框释放时调用 ()方法向 注销 、所有已经注册的 在释放时没有注销,造成资源的不可回收。 反例: 第页 仅在初始化时注册了 的 。没有样放。 正例: 首先定义静态的 然后在初始化时注册 最后在资源释放时注销。 注意:组件库中的 提供了创建 的快捷方法,采用这种方法创建 后,最好在资源释放时也显式的调用该类的 ()方法释放资源。 4.3 底层内存泄漏 的 类存在 该类的 和 方法使用了 做鉴別线程的日志记录操作,但在使用后没有调用 ,从而造成 类对象的泄漏 对象中包含 对象, 对象中由可以 存储各种各样的 。如果线程对象在先前的操作中调用过 的方法,则线程 将保留对被的对象的引用。而 正是由于 线程接收连接后生 成的 线程将其设置到自己的局部存储中,而被 用。由于线程被用,所以也就释放不」 引用线程的原因如下 中包含一个静态的 用于记录调用操作的线程和参数间的关 系。每当一个新线程调用操作,都会以该线程对应的 对象为在 中创建一个 对。该 只有调用 方法才会从 中删掉 在平台环境中,对于来自客户端的每次调用在服务端会产生一个服务 线程,该线程在调用到的方法前会调用 的 或 方法 于是就造成了内存泄漏 总结 内存泄漏影响严重而乂难以彻底清査,所以需要大家在编程阶段就把这个问题重视起 来,首先要有存在内存泄漏这个意识,学会使用测试工具,在编码完成后自己进行测 试,不过更重要的还是养成良好的编程习惯,把问题提前避免掉,这里有些建议: 第页 使用了 或者 这些方法的地方注意使用完后要 或者 减少对象间的相互依赖,很多内存泄漏都是因为对象相互依赖太复杂,退岀时清理 不彻底造成的。 留意全局地静态类,特別是集合类,如果你把对象放在里面,不去显示的消除,那 么这个对象释放就只有等虚拟机退出了。 客户端编程一定注意窗口关闭(当然不是隐藏)时使用 对」大数据量处理的地方,对象释放时建议手工去把关系打断,这样可以让虚拟札 最快的回收内存 参考文献 《的内存泄漏》 第页

...展开详情
试读 10P 如何解决Java内存泄漏
立即下载 低至0.43元/次 身份认证VIP会员低至7折
抢沙发
一个资源只可评论一次,评论内容不能少于5个字
关注 私信 TA的资源
上传资源赚积分,得勋章
最新推荐
如何解决Java内存泄漏 39积分/C币 立即下载
1/10
如何解决Java内存泄漏第1页
如何解决Java内存泄漏第2页

试读结束, 可继续读1页

39积分/C币 立即下载 >