Java的内存泄漏

来源:互联网 发布:风险矩阵分析法 介绍 编辑:程序博客网 时间:2024/06/07 12:33
       问题的提出
 
      Java的一个重要点就是通垃圾收集器(Garbage CollectionGC)管理内存的回收,程序不需要通过调用函数来放内存。因此,很多程序员认为Java不存在内存泄漏问题,或者认为即使有内存泄漏也不是程序的任,而是GCJVM问题。其这种想法是不正确的,因Java也存在内存泄露,但它的表C++不同。
 
      随着越来越多的服器程序采用Java,例如JSPServlet EJB等,服器程序往往期运行。另外,在很多嵌入式系中,内存的量非常有限。内存泄露问题也就得十分关键,即使次运行少量泄漏,期运行之后,系也是面的危
 
       Java是如何管理内存
 
      了判断Java中是否有内存泄露,我首先必了解Java是如何管理内存的。Java的内存管理就是象的分配和问题。在Java中,程序需要通过关键new为每象申内存空 (基本型除外),所有的象都在堆 (Heap)中分配空
 。另外,象的放是由GC决定和行的。在Java中,内存的分配是由程序完成的,而内存的放是有GC完成的,这种收支两条线的方法确实简化了程序的工作。但同,它也加重了JVM的工作。也是Java程序运行速度慢的原因之一。因GC了能正确象,GC须监一个象的运行状,包括象的申、引用、被引用、赋值等,GC都需要控。
 
      监视对象状了更加准确地、及象,而象的根本原就是该对象不再被引用。
 
 
      了更好理解GC的工作原理,我可以将象考虑为有向点,将引用系考虑为图的有向,有向从引用者指向被引象。另外,线象可以作一个的起始点,例如大多程序从main行,那么该图就是以main始的一棵根。在个有向中,根点可达的象都是有效象,GC将不回收象。如果某个 (通子)个根点不可达(注意,该图为有向),那们认为这()象不再被引
 用,可以被GC回收。
 
      以下,我们举一个例子明如何用有向表示内存管理。于程序的一个刻,我都有一个有向表示JVM的内存分配情况。以下右,就是左程序运行到第6行的示意
 
 
      Java使用有向的方式行内存管理,可以消除引用循问题,例如有三个象,相互引用,只要它和根程不可达的,那GC也是可以回收它的。这种方式的点是管理内存的精度很高,但是效率低。另外一常用的内存管理技是使用数器,例如COM模型采用数器方式管理构件,它与有向相比,精度行低(难处理循引用的问题),但行效率很高。
 
       Java中的内存泄露
 
      下面,我就可以描述什是内存泄漏。在Java中,内存泄漏就是存在一些被分配的象,象有下面两个特点,首先,象是可达的,即在有向中,存在通路可以与其相;其次,象是无用的,即程序以后不会再使用象。如果两个条件,象就可以判定Java中的内存泄漏,象不会被GC所回收,然而它却占用内存。
 
      C++中,内存泄漏的范更大一些。有些象被分配了内存空,然后却不可达,由于C++中没有GC些内存将永收不回来。在Java中,些不可达的象都由GC负责回收,因此程序不需要考虑这部分的内存泄露。
 
      分析,我得知,C++,程序需要自己管理点,而Java程序只需要管理就可以了(不需要管理点的)。通过这种方式,Java提高了程的效率。
 
      因此,通以上分析,我知道在Java中也有内存泄漏,但范C++要小一些。因Java言上保,任何象都是可达的,所有的不可达象都由GC管理。
 
      于程序GC基本是透明的,不可的。然,我只有几个函数可以访问GC,例如运行GC的函数System.gc(),但是根据Java范定 函数不保JVM的垃圾收集器一定会行。因,不同的JVM实现者可能使用
 不同的算法管理GC。通常,GC线程的级别较低。JVMGC的策略也有很多,有的是内存使用到达一定程度GC始工作,也有定时执行的,有的是平缓执GC,有的是中断式GC。但通常来,我不需要些。除非在一些特定的合,GC行影响用程序的性能,例如于基于Web实时,如网等,用不希望GC突然中断用程序行而行垃圾回收,那需要GC的参数,GC的方式放内存,例如将垃圾回收分解一系列的小步骤执行,Sun提供的HotSpot JVM就支持一特
 性。
 
      下面出了一个简单的内存泄露的例子。在个例子中,我Object象,并将所申象放入一个Vector中,如果我们仅仅释放引用本身,那Vector仍然引用该对象,所以GC是不可回收的。因此,如果象加入到Vector后,Vector除,最简单的方法就是将Vectornull
 
      Vector v=new Vector(10);
      for (int i=1;i<100; i++)
      {
      Object o=new Object();
      v.add(o);
      o=null;
      }
      //,所有的Object象都没有被放,因为变v引用象。
 
       如何检测内存泄漏
 
      最后一个重要的问题,就是如何检测Java的内存泄漏。目前,我通常使用一些工具来检查Java程序的内存泄漏问题。市上已有几种专业检查Java内存泄漏的工具,它的基本工作原理大同小异,都是通过监测Java程序运行,所有象的申放等作,将内存管理的所有信息统计、分析、可化。开发将根据些信息判断程序是否有内存泄漏问题些工具包括Optimizeit ProfilerJProbe ProfilerJinSight , Rational 公司的
 Purify等。
 
      下面,我简单Optimizeit的基本功能和工作原理。
 
      Optimizeit Profiler版本4.11支持ApplicationAppletServletRomote
 Application类应用,并且可以支持大多数型的JVM,包括SUN JDK系列,IBMJDK系列,和JbuilderJVM等。并且,该软件是由Java写,因此它支持多操作系Optimizeit系列包括Thread DebuggerCode Coverage两个工具,分用于监测运行
 线程状和代覆盖面。
 
      置好所有的参数了,我就可以在OptimizeIt境下运行被程序,在程序运行程中,Optimizeit可以监视内存的使用曲线(如下),包括JVM的堆(heap)的大小,和实际使用的内存大小。另外,在运行程中,我可以随时暂停程序的运行,甚至GCGC行内存回收。通内存使用曲线,我可以整体了解程序使用内存的情况。这种监测对期运行的用程序非常有必要,也很容易发现内存泄露。
 
 
      在运行程中,我们还可以从不同观查内存的使用情况,Optimizeit提供了四方式:
 
 
      角。 是一个全面的角,我可以了解堆中的所有的象信息(数量和种类),并统计、排序,过滤。了解相关对象的化情况。
      方法角。通方法角,我可以得知种类象,都分配在哪些方法中,以及它的数量。
      角。定一个象,通过对角,我可以示它的所有出引用和入引用象,我可以了解象的所有引用系。
      引用 定一个根,通引用,我可以示从该顶点出的所有出引用。
 
      在运行程中,我可以随时观察内存的使用情况,通过这种方式,我可以很快找到那些期不被放,并且不再使用的象。我过检查这象的生存周期,确其是否内存泄露。在践当中,找内存泄露是一件非常麻的事情,它需要程序员对整个程序的代清楚,并且需要丰富的调试经验,但是于很多关键Java程序都是十分重要的。
 
      上所述,Java也存在内存泄露问题,其原因主要是一些然不再被使用,但它仍然被引用。了解决问题,我可以通过软件工具来检查内存泄露,检查的主要原理就是暴露出所有堆中的象,程序员寻找那些无用但仍被引用的象。

 

原创粉丝点击