收稿日期:2005-09-29;修返日期:2005-11-26
基金项目:国家自然科学基金资助项目(60373016);国家“863”计划资助项目(2004AA112030)
Java 程序内存泄漏综述
*
贾晓霞1
,吴 际1
,金茂忠1
,李郭欢
2
(1.北京航空航天大学计算机学院,北京100083; 2.西南通信研究所,四川成都610041)
摘 要:从与C/C ++内存泄漏对比的角度分析了J a va 内存泄漏问题,详细介绍了J ava 内存泄漏的相关
研究和工具,探讨了当前研究和工具中存在的不足并分析了其原因,总结了内存泄漏相关领域研究的发展趋势。关键词:内存泄漏;垃圾回收;内存低效;J ava
中图法分类号:TP311 文献标识码: A 文章编号:1001-3695(2006)09-0001-03
Over view s on M em ory Leak in J ava Progra m
J IA Xia o-xia 1,WU J i 1,J IN Ma o-zhong 1,LI Guo-hua n 2
(1.College of C omputer Science &Technology,Beijing University of Aeronautics &Astr onautics,Beijing 100083,China;2.Southwes t Commu-nication Ins titute,Chengdu S ichuan 610041,China)
Abst ract :The m em ory leak in both J av a progra m s a nd C/C ++progra m s is com pared in this pa per.Related w ork a nd tools
of J a va progra m m em ory lea k a re introduced in det ail at first .Then t he draw backs of prent solut ions to the m em ory lea k in J ava progra m s a re out lined and the potential reas ons a re explored.Finally ,the future direct ion of the corresponding rearch is out lined.
Key wo rds:Mem ory Leak;Garbag e Collect ion;Mem ory Low Us age;J a va
1 Java 内存泄漏的基本概念
程序执行过程中,由于很多变量所需的内存空间在编译时无法确定,操作系统需要为这些变量动态地分配内存。相应地,许多编程语言都有其内存分配/回收机制,变量被创建时分配内存,变量不再需要时释放其所占内存。本文在分析及简要对比C/C ++与J ava 内存机制的基础上阐述了J a va 内存泄漏问题。
C/C ++程序运行时,New/Malloc 等分配操作将内存块取到工作空间;Delete/Free 等释放操作将内存块送回自由空间。程序员通过精心设计分配和释放操作保证已分配的内存块或者仍在工作空间,或者被送回自由空间。但是,动态空间中已分配、未被释放、丢失了访问路径的内存块,由于无法再被访问而泄漏。C/C ++内存泄漏是指程序中已动态分配的堆内存由于某种原因未释放或无法释放,造成系统内存的浪费
[1]
。
J ava 内存机制与C/C ++的一个主要不同是J a va 内存回收由J VM 提供的垃圾收集器(Garbag e Collect or,GC)自动完成。J ava 程序员只需通过内存分配操作创建对象,而无须关心对象占用的内存何时被回收。GC 监控对象的运行状态,其中一种是采用可达测试(Rea chability Test)
[2]
检测对象是否从根
(根Root 是指J a va 堆的初始入口点。根对象有五种类型:类的静态成员、J ava 方法、本地栈方法、本地方法中的全局变量、线程的异常处理程序中的异常)可达。GC 回收对失去引用、从根不可达的对象但仍被引用(直接或间接被根引用)的对象不一定仍有用;对已无用对象的引用导致J a va 内存泄漏。J a va
内存泄漏是指逻辑上已无用的对象,由于被其他仍有用的对象引用,导致其无法被回收。常见的泄漏如废弃的聚集引用(Obsolete C ollect ion References):对象加入到一个聚集中,当其不再需要时并没有被移去,当该聚集用S ta tic 声明且在程序的整个生命周期存在时问题尤为突出。
从上述介绍可看到,C/C ++与J av a 的内存泄漏问题并不相同,其不同表现形式[3]如图1所示。
图1表示程序在某时刻运行的内存状况,其中节点代表对象,边表示对象间的引用关系。有用对象是指从该运行时刻开始,程序的路径将会覆盖的对象,它对程序行为依然有影响;可达对象是指从该运行时刻开始,根对象可引用到的对象。
可以看到:①C/C ++泄漏对象是指已分配,但不可达的对象;J ava 泄露对象是不再有用,却仍可达的对
象。②C/C ++中对象不可达导致的泄漏在J ava 中被GC 回收,因此,与C/C ++相比,J ava 内存泄漏的范围小,也更难检测。③C/C ++内存泄漏关注指针及程序变量使用的内存;而对J a va 程序而言,某些不再有用的对象被其他仍有用的对象引用导致泄漏。所以,J a-va 内存泄漏检测关注对象间的引用关系及对象是否依然有用。
2 Java 内存泄漏现状
在分析J VM 垃圾回收机制的基础上介绍J a va 内存泄漏的研究现状和工具。
・1・2006年第9期贾晓霞等:J ava 程序内存泄漏综述
根对象
图1C/C++和Java 内存泄漏的不同表现形式
2.1JV M垃圾回收机制福字倒贴的传说
Sun’s J ava2S DK采用标记及清除(Ma rk and S weep)算法(其他常用的GC算法可参见文献[4])进行可达检测并完成垃圾回收。其内存回收过程分为两个阶段:①在标记阶段,堆中所有对象首先被标记为“Fal”,可达检测从根出发依照引用关系追踪所有对象,若对象可达则将其标记改为“True”;②在回收阶段,标记依然为“Fa l”的对象可被回收,如果该对象没有Finalize方法,其所用内存立刻被回收,否则该对象的F inalize方法首先被执行(J a va类的Fina lize方法有些类似于C++类的析构函数,但Fina lize方法的执行有不确定性,可能导致对象复活,并不能达到与C++析构函数同样的效果,所以并不推荐使用)[5]。
Finaliz e方法被执行时,该对象被GC放入终结队列(Fina-lize Queue),并保留在该队列中直至J VM启动一个终结线程(Fina lizer T hread)。终结线程将对象从队列中移出,并执行其F inalize方法。接着,GC进行第二次可达检测,以检测Finalize 方法是否新创建了对象引用。如果对象没有通过第二次可达检测(其标记依然为“Fal”),GC释放该对象占用的内存。
产生内存泄漏的原因是不再有用的对象被其他依然有用的对象引用,导致其可以通过可达测试,从而无法被回收。所以,很多针对J a va内存泄漏的研究通过分析对象是否有用及对象间的引用关系进行。下面介绍J av a内存泄漏研究现状。
2.2Java内存泄漏研究现状
黑玫瑰图片当前对J ava内存泄漏检测的研究非常多,本文主要从以下几方面介绍:
(1)针对对象是否依然有用
对J ava程序而言,很多泄漏的对象都是在一些自包含(S elf-cont ained)的操作中临时创建的。操作结束后,这些对象由于被其他依然有用的对象引用,导致无法被GC回收[6]。为了检测这类内存泄漏,文献[6]提出了一个基本的内存泄漏场景:对一些临时对象,给出其期望的生命周期,当对象的存活期限超出其期望的生命周期时,该对象便是一个可疑的泄漏对象。文献[7]针对J ava中的数组,提出一个结合前向数据流分析和后向控制流分析的算法标志变量间的关系,并确定数组中元素的有用区域:算法给出各程序点相关的变量间的约束关系以及在该点依然有用的数组元素,GC利用数组间的约束关系回收不再有用的数组变量。
(2)针对对象间的引用关系
文献[8]提出一种基于堆中对象的引用图,检测J ava应用程序内存泄漏的轻量级自适应方法。由于堆快照中数据量巨大,分析堆中的结构(Da ta S t ructure,如一个DOM对象),若该结构在堆中迅速增长,则其可能被泄漏。对可能泄漏的结构定义了一系列度量信息,给出其可能泄漏的优先级,选定某个结
构作为候选,寻找其中尽可能以一致方式演化的区域。设计了一个轻量级的方法在程序实际运行时跟踪这些区域(Region),从而分析可疑的内存泄漏。基于堆快照,裁减对象引用图,分层次分析得出可疑区域,并在程序实际执行时采用较少的代价确认分析得到的可疑区域是否为内存泄漏。
(3)分析根对象提高内存检测效率
GC算法从根对象出发进行可达检测,若某对象从根可达,则保留之。因此,对GC而言,根对象的选择很重要,如果根对象选择较保守,则会有很多本应被回收的内存被保留。文献[9]关注可能成为根对象的局部变量,进行类型分析(Ty pe A-na lysis)以获得类型精确的根对象,同时分析变量是否有用使仍可用的对象成为根对象。
(4)垃圾回收算法
除了前面提到的标记及清除算法,还有很多其他的GC算法,如按代回收的回收算法将堆划分为多个子堆,每个子堆为一“代”对象服务。最年幼的那一代进行最频繁的垃圾回收,年幼对象经历了几次垃圾回收仍然存活就成长一代,移动到另一个子堆中去,如J DK1.4.1的堆就包括年轻代的堆、年长代的堆和永久保留的堆[10]。自适应回收算法则监视堆中的情况,相应地调整某种简单垃圾回收算法的参数,或快速转换到另一种算法,或把堆分为子堆,不同子堆使用不同的GC算法。
上述从几个不同的角度介绍了J av a内存泄漏的已有研究,通过对变量是否可用的分析将已不再有用的对象回收;关注对象引用图得到可疑对象,然后通过跟踪实际运行分析之;尽可能缩减GC根对象则可以提高GC的效率;垃圾回收算法的研究也旨在提高GC效率。
2.3 Java内存泄漏检测工具
J av a内存泄漏检测工具获取程序运行时的内存分配/回收信息,关注堆使用状况并分析这些信息以发现可疑对象。有两种不同的方法可获得内存/分配信息[11]:①采用J VMTI(J a va Virtual Machine Tools Int erfa ce)或其前身J VMPI(J a va Virt ual Machine Profiling Int erfa ce)。②进行字节码插装。J VMPI是J a-va虚拟机与运行中剖析代理间的双向函数调用接口:一方面虚拟机通过J VMPI通知剖析代理各种事件;另一方面剖析代理通过J VM PI控制和请求更多的信息。字节码插装方法则对插装后的字节码进行预处理获取所需信息。目前大多数工具均是基于J VM PI获取J a va程序运行时刻信息(堆信息及对象的分配、引用关系等)。下面简要介绍其中的三个工具:
(1)J Probe Mem ory Debugger
利用J Probe Mem ory Debug ger[12]检测内存泄漏时,用户设定用例(U Ca )的结果假设与真实结果进行对比发现可疑对象,分析快照(J ava虚拟机某个时刻堆的剖面)间的差异发现可疑对象。J Probe Mem ory Debugg er的堆快照提供类视图(Class View)和实例视图(Insta nce View),视图中提供
的信息包括类实例个数、实例变化个数、已分配的内存数等。对某个类实例,可观测其引用树(Reference Tree)及引用者树(Referrer Tree),并在源码存在时获得其分配位置。当某个实例为可疑的泄漏对象时,用户可利用内存泄漏医生(Mem ory L eak Doc-tor)寻找导致泄漏的引用,用户可利用J Probe提供的被移除引用的列表发现内存泄漏的真正原因。
(2)J Rockit Mem ory Lea k Det ect or
J Probe Mem ory Debugg er[13]基于J VMPI转储堆信息获得堆快照,对其进行离线分析以检测是否存在内存泄漏。运行时通过J VMPI获取信息并转储堆会降低应用程序的运行速度。与J Probe不同,J Rockit Mem ory Lea k Detect or是一种实时检测基于BEA J VM运行的J av a程序内存泄漏的工具,它内嵌于B EA J Rockit J VM内,在程序运行时即进行交互式的分析。J Rockit
・
2
・计算机应用研究2006年溪水声音怎么形容
通过J Rockit管理控制台(J Rockit Manag em ent Console)从运行的J VM中获得信息。J VM进行一次GC操作,J Rockit M om ory L eak Detect or便获取数据并进行一次趋势分析(Trend Analy-sis)。趋势分
析描述堆中最常用的对象类型(或用户指定的关注类的对象)、对象当前占用的内存数、占用内存的增长趋势、对象的实例个数等。增长最快的对象是值得怀疑的泄漏对象。对可疑对象,分析其相互引用关系及指向特定实例的引用来发现导致泄漏的可疑引用。与J Probe相比,J Rockit缺乏完整的对象引用图以及对象的分配轨迹(Allocat ion Traces)。
(3)Purify
用户可利用Purify[14]在内存稳定使用时获取堆快照作为今后快照比较的基准,并在执行可能导致问题的代码后再次拍摄快照。快照包含方法和对象层次的内存使用情况,基于快照差异分析可得到可能包含内存泄漏的方法或可能的泄漏对象。P urify的调用图(Ca ll Graph)突出显示泄漏内存最多的方法并显示每一方法的详细数据。用户可查看对象调用的每一方法并按需将对象排序;从对象列表视图查看对象的内存使用状况,以决定大量占用内存的对象是否需要被释放。
从上述分析可看到,J Probe和Purify都是基于转储的堆快照进行离线分析,而J Rockit集成于J VM内进行交互式的在线分析。J Probe提供内存泄漏医生,帮助用户定位可能引发内存泄漏的引用;而Purify则提供方法的内存使用信息,用户结合该信息及对象的内存使用信息可在方法层次寻找引发内存泄漏的原因。除了上述三种外,还有很多J a va内存泄漏检测工具和J ava P rofiler工具,如J Profiler[15]的最新版本J Profiler4支持J VMTI;HeapRoots[16]提供命令行的交互接口分析堆快照; Hprof,Heapdum p
s,FindRoot s和Sv cdum ps[17]检测运行于Web-sphere平台应用程序的内存泄漏;Opt im izeit Ent erpri S uit e[18],IBM J Insight[19],Ora cle J Dev eloper[20]等都提供对J a va 堆信息的提取以帮助用户检测内存泄漏。也有一些开源的J a-va Profiler,如C ouga ar M em ory Profiler,J Mem Prof,J MP等[21]。
3 当前研究与工具的不足
针对J ava内存泄漏产生的两个必要条件,即对象可达和对象不再有用,很多研究通过为临时对象设定期望的生存周期以及采用约束图表示变量之间的关系来判断该对象是否仍有用;或者分析对象或类间的引用关系,在发现可疑类或对象后通过对其引用关系的分析发现内存泄漏的根源。而大多数J a-va内存泄漏检测工具则基于J VMPI获取J a va程序运行时的堆信息,基于堆中各类对象、对象实例及各类对象占用内存的情况分析内存泄漏,并提供引用图和对象分配踪迹栈辅助用户发现内存泄漏的产生原因。但已有研究和工具还存在以下不足:
(1)研究大都集中于如何发现内存泄漏,但如何对已发现内存进行诊断并去除该泄漏依然是个很难的问题;
(2)大多数工具要求用户对程序有一定的认识或期望,否则难以从工具提供的海量信息中发现泄漏内存的踪迹;
(3)工具可以对发现泄漏内存提供有价值的信息,但无法对如何诊断泄漏提供有价值的信息。
笔者认为,J ava内存泄漏检测研究是基于对象间的引用关系及对象是否依然有用来检测内存泄漏或提高GC效率的,但这些信息无法为诊断并去除已检测到的泄漏提供更多的帮助。J av a内存泄漏检测工具大多基于堆快照中类、对象及其所占内存等信息帮助用户检测内存泄漏,基于这些信息同样很难诊断检测到的泄漏。这些研究和工具没有描述并分析对象的行为是其中一个原因。
为了解决这个问题,我们关注J av a程序的一个场景:同一类的多个对象,使用逻辑的不同导致其行为的不同,行为的不同可能使得某些对象被回收,而某些对象没有。笔者提出对象生存期行为模型来描述对象从创建开始到被销毁为止的整个时间段内的行为,其中对象的行为是采用对象所响应的外部事件以及所发出的请求事件来刻画的。基于泄漏对象和未泄漏对象行为差异的分析可获得可能导致泄漏的对象行为,也就是对象响应的外部事件或发出的请求事件,这是笔者正在进行的研究,在该基础上可深入研究对象行为以诊断更多场景的内存泄漏。
4总结
内存泄漏可能导致系统性能下降而日益成为广泛研究的问题。除了不再有用的对象被其他依然有用的对象引用导致内存泄漏外,经分析发现,J av a程序中可能存在一种长时间空闲对象。这些对象生存时间很长,但其活动却只集中于某个短的时间段(该对象长时间处于空闲无活动状态),导致相应的内存
长时间无法循环使用。J a va程序某些情况下会出现大量生存期很短的临时对象,当其占用内存较大时可能导致GC频繁启动,消耗大量的程序时间。本文将内存泄漏以及上述两种情况统称为J av a内存的低效使用。J ava内存的低效使用一方面可能导致程序在运行中的某个时刻消耗完J VM所能申请的所有内存而使J VM崩溃;另一方面可能导致频繁的GC活动而使程序的运行效率急剧下降,这在时间和空间两个角度上均会产生严重的系统性能问题。
内存泄漏的检测已得到广泛的研究,支持工具也很多,但检测内存泄漏的研究或工具采用的信息都无法很好地帮助诊断内存泄漏,如何诊断已泄漏内存是个值得研究的问题。对象生存期行为模型对如何诊断泄漏做了有益的探讨,也正是笔者正在进行的研究。如何更好地诊断J a va内存泄漏、如何将内存泄漏问题延伸到内存的低效使用以更好地解决J ava程序系统性能下降的问题将是内存泄漏相关领域的重要研究方向。参考文献:
[1]he Ja rgon Dictionary[E B/OL].info.astiran/jar gon/
ter ms/m/memory_leak.html,2004.
[2]QUES T公司.J Probe Memor y Debugger Developer’s Guide[R].
2005.
[3]Ed Lycklama.Does J ava Technology Have Memor y Lea ks?[R].
Chief Technology Officer,KL Group Inc.,2005.
[4]Paul R Wilson.Unipr ocessor Garbage Collection Techniques[C].St.
M alo:International Workshop on Memory Manag ement,1992.1-42. [5]Br uce E ckel.Thinking in J ava(2nd edition)[M].候捷.北京:机械
工业出版社,2002.
[6]Wim De Pa uw,Gary S evitsky.Visua lizing Refer ence Patterns for Solving
M emor y Lea ks in Ja va[C].Lisbon:Pr oceedings of the13th E ur opean
Conference on OO Prog ramming,1999.116-134.(下转第17页)
・
3
・
第9期贾晓霞等:J ava程序内存泄漏综述
尤其对于工科院校,长期以来对控制原理、电路原理和力学原理等需要形象教学的科目,由于实验室条件限制,大多数仍停留在文字教学阶段,而国内几千家院校的数量也说明电教市场是一个不容忽略的市场。
3 总结
将工业控制中的组态思想应用到一类软件系统的开发中,借鉴工业控制自动化领域中的组态思想进行软件开发。在传统开发方式的基础之上,对同一类的应用系统进行分析、归类、抽象,建立组态软件平台,采用设计的组态平台来组态开发用户应用系统,与传统方法相比减少了很多中间环节,目标的准确性也将大大提高,开发周期大为缩短。由于组态平台的使用,对于系统规划准确性的要求将有所降低,应该说这样更符合人们做事的习惯,人类能够具有预见性,但预见的准确性却很不理想,许多发明创造都是经过反复试验来获得的。系统的开发也同样,系统本身就是对事物规律的抽象,当人们没有见到其完整面目时,就对其进行准确的定义,应该说是十分困难的事情,许多系统开发的失败无不与此相关。组态平台所具有的方便维护升级改造的功能就能很好地解决这样的问题,其机制允许用户从简到繁,从容易到复杂,逐步完善所开发的系统,并可不断地添加新的功能以适应新的需求,从而延长系统的生命周期。
法国著名大学
总之,本文分析了一类软件系统开发的新模式,即基于组态思想开发软件系统。组态技术作为软件开发的新手段是时代发展的产物,必将取得进一步突破。参考文献:
[1]柴跃廷,刘义.应用软件系统开发[M].北京:清华大学出版社,
1999.
[2]林威汉,高春光,张海涛.组态软件的现状与未来[J].电气时代,
绿豆糕的做法2002,(6):9-12.
[3]马国华.监控组态软件及其应用[M].北京:清华大学出版社,
2001.
[4]李朝辉,邓贵仕,张光前,等.基于COM/DCOM的电子商务系统
组态实现技术[J].计算机应用研究,2004,21(4):186-188. [5]李朝辉,邓贵仕,李文立.管理信息系统组态开发模式探讨[J].计
算机工程与应用,2002,38(7):39-42.
[6]耿玉水,鲁芹.管理信息系统组态平台的研究[J].山东轻工业学
院学报,2003,17(4):1-5.
[7]钱玲,张友良,那正平.基于Web的虚拟制造系统的结构建模组
态技术[J].中国机械工程,2002,13(21):1848-1851.
[8]张仁杰,周麟.基于网际组态软件Web Access的远程监控实验系
统[J].工业控制计算机,2002,15(12):22-23.
[9][美]M ikey Willliams.Windows2000编程技术内幕[M].前导工
作室.北京:机械工业出版社,1999.2-11.
作者简介:
杨亚罗(1978-),男(白族),云南大理人,博士研究生,主要研究方向为制造自动化、组态软件开发;王润孝(1957-),男,陕西蒲城人,教授,博导,主要研究方向为先进制造技术、机电控制及自动化;库祥臣(1968-),男,河南漯河人,讲师,硕士,主要研究方向为机电一体化、数控技术;王力刚(197
5-),男,黑龙江哈尔滨人,博士研究生,主要研究方向为机器人技术。
(上接第3页)
[7]S haham,E K Kolodner,M Sag iv.Automatic Remov al of Arra y
Memory Leaks in J ava[C].Berlin:Compiler C onstruction,the9th In-ternational Conference,volume1781of Lecture Notes in Computer Science,2000.50-66.
[8]N M itchell,G Sevitsky.Lea kbot:An Automa ted and Lightweight
Tool for Diagnosing M emory Leaks in Large J av a Applications[C].
Da rmstadt:E uropean Conference on Object-Oriented Progr amming (ECOOP),Lectur e Notes in C omputer S cience,Springer-Verlag, 2003.351-377.
宝宝胎教
[9]Agen O,Detlefs D,MOSS J E B.Gar bage C ollection a nd Local
Va riable Typepr ecision a nd Liv eness in J ava Virtua l Machines[C].
New Yor k:Programming Lang uage Design a nd Implementation(PL-DI),1998.269-279.
[10]Nagendr a Nagara jayya,J Steven M ayer.Improving J ava Application
Perfor mance and S calability by Reducing Garbage Collection Times and Sizing Memor y Using J DK1.4.1[E B/OL].developer s.
[11]Sta ffa n Larn.M emory Leaks,Be Gone[EB/OL].
/pub/a/2005/06/m emory_leaks.html,2005-06. [12]Quest J Probe M emory Debugger[E B/OL].,
2005.
[13]BEA J Rockit Memor y Leak Detector[EB/OL].ww w.bea.
com,2005.
[14]IB M Purify[EB/OL]./softwar e/awd-
tools/purify/win/,2005.
[15]EJ-technolog ies’JPr ofiler[EB/OL].www.ej-technolog ies.
com/products/jprofiler/overview.html,2005.
[16]HeapRoots[EB/OL].www./tech/hea-
proots,2005.
[17]Steve Ea ton,Hany Salem,Fr eder ic M ora.Finding J av a M emory Leaks
in WebS phere Application S erver[EB/OL].w /
developer wor ks/websphere/libr ary/techar ticles/0403_mora/0403_
mor a.html,2005.
[18]Optimizeit Enterpri Suite[EB/OL]./us/
pr oducts/optimizeit/,2005.
[19]IBM J Insight[EB/OL].ar /jinsight/,
2005.
[20]Oracle J Developer[E B/OL]./technology/
pr oducts/jdev/,2005.
[21]Open S our ce Pr ofilers for J av a[EB/OL].ww w.manageability.
org/blog/stuff/open-source-profilers-for-java/view,2005-10.
作者简介:
贾晓霞(1976-),女,山西原平人,博士研究生,主要研究方向为软件测试方法、软件工程、面向对象技术;吴际(1974-),男,安徽六安人,讲师,博士,主要研究方向为软件测试方法、软件工程、面向对象技术、编译技术、自然语言处理技术;金茂忠(1941-),男,上海人,教授,博导,主要研究方向为编译技术、软件测试方法、软件工程、面向对象技术;李郭欢(1982-),男,四川成都人,硕士研究生,主要研究方向为密码学、软件测试。
・
7手机卡服务密码
1
・
建设银行个人网上银行登录入口
第9期杨亚罗等:组态概念发展的新趋势