JAVA垃圾回收姜荣萍一.谁在做GarbageCollection在C++里,是系统在做垃圾回收;而在Java里,是Java自身在做。在C++里,释放内存是手动处理的,要用delete运算符来释放分配的内存.是应用认为不需要某实体时,就需用delete告诉系统,可以回收这块空间了。会导致以下弊端:程序员有可能因为粗心大意,忘记及时释放无用变量的内存,从而影响程序的健壮性。程序员有可能错误地释放核心类库所占用的内存,导致系统崩溃或者内存泄漏的话题。在Java语言中,内存回收的任务由Java虚拟机来担当,而不是由Java程序来负责。在程序的运行时环境中,Java虚拟机提供了一个系统级的垃圾回收器线程,它负责自动回收那些无用对象所占用的内存,这种内存回收的过程被称为垃圾回收(GarbageCollection)。优点:把程序员从复杂的内存追踪、监测和释放等工作中解放出来,减轻程序员进行内存管理的负担。防止系统内存被非法释放,从而使系统更加健壮和稳定。特点:•只有当对象不再被程序中的任何引用变量引用时,它的内存才可能被回收。•程序无法迫使垃圾回收器立即执行垃圾回收操作。•当垃圾回收器将要回收无用对象的内存时,先调用该对象的finalize()方法,该方法有可能使对象复活,导致垃圾回收器取消回收该对象的内存。对象的状态转换图当一个对象(假定为Sample对象)被创建后,只要程序中还有引用变量引用它,那么它就始终处于可触及状态当Java虚拟机执行完所有可复活对象的finalize()方法后,假如这些方法都没有使Sample对象转到可触及状态,那么Sample对象就进入不可触及状态。只有当对象处于不可触及状态时,垃圾回收器才会真正回收它占用的内存。二.垃圾收集的算法分析1、引用计数法(ReferenceCountingCollector2、tracing算法(TracingCollector)3、compacting算法(CompactingCollector)4、copying算法(CopingCollector)5、generation算法(GenerationalCollector)6、adaptive算法(AdaptiveCollector)垃圾收集首选需要确定从根开始哪些是可达的和哪些是不可达的,从根集可达的对象都是活动对象,它们不能作为垃圾被回收,这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件,应该被回收。常用的算法三、透视Java垃圾回收1、命令行参数透视垃圾收集器的运行2、使用System.gc()可以不管JVM使用的是哪一种垃圾回收的算法,都可以请求Java的垃圾回收。在命令行中有一个参数-verbosegc可以查看Java使用的堆内存的情况,它的格式如下:java-verbosegcclassfile可以看个例子:classTestGC{publicstaticvoidmain(String[]args){newTestGC();System.gc();System.runFinalization();}}在这个例子中,一个新的对象被创建,由于它没有使用,所以该对象迅速地变为可达,程序编译后,执行命令:java-verbosegcTestGC后结果为:[FullGC168K-97K(1984K),0.0253873secs]机器的环境为,Windows2000+JDK1.3.1,箭头前后的数据168K和97K分别表示垃圾收集GC前后所有存活对象使用的内存容量,说明有168K-97K=71K的对象容量被回收,括号内的数据1984K为堆内存的总容量,收集所需要的时间是0.0253873秒(这个时间在每次执行的时候会有所不同)。下面这个例子向大家展示了垃圾收集所经历的过程classChair{staticbooleangcrun=false;staticbooleanf=false;staticintcreated=0;staticintfinalized=0;inti;Chair(){i=++created;if(created==47)System.out.println(Created47);}protectedvoidfinalize(){if(!gcrun){gcrun=true;System.out.println(Beginningtofinalizeafter+created+Chairshavebeencreated);}if(i==47){System.out.println(FinalizingChair#47,+SettingflagtostopChaircreation);f=true;}finalized++;if(finalized=created)System.out.println(All+finalized+finalized);}}publicclassGarbage{publicstaticvoidmain(String[]args){if(args.length==0){System.err.println(Usage:\n+javaGarbagebefore\nor:\n+javaGarbageafter);return;}while(!Chair.f){newChair();newString(Totakeupspace);}System.out.println(AfterallChairshavebeencreated:\n+totalcreated=+Chair.created+,totalfinalized=+Chair.finalized);if(args[0].equals(before)){System.out.println(gc():);System.gc();System.out.println(runFinalization():);System.runFinalization();}System.out.println(bye!);if(args[0].equals(after))System.runFinalizersOnExit(true);}}上面这个程序创建了许多Chair对象,而且在垃圾收集器开始运行后的某些时候,程序会停止创建Chair。由于垃圾收集器可能在任何时间运行,所以我们不能准确知道它在何时启动。因此,程序用一个名为gcrun的标记来指出垃圾收集器是否已经开始运行。利用第二个标记f,Chair可告诉main()它应停止对象的生成。这两个标记都是在finalize()内部设置的,它调用于垃圾收集期间。另两个static变量--created以及finalized--分别用于跟踪已创建的对象数量以及垃圾收集器已进行完收尾工作的对象数量。最后,每个Chair都有它自己的(非static)inti,所以能跟踪了解它具体的编号是多少。编号为47的Chair进行完收尾工作后,标记会设为true,最终结束Chair对象的创建过程。四、注意:(1)不要试图去假定垃圾收集发生的时间,这一切都是未知的。(2)Java中提供了一些和垃圾收集打交道的类,而且提供了一种强行执行垃圾收集的方法--调用System.gc(),但这同样是个不确定的方法。。(3)挑选适合自己的垃圾收集器。一般来说,如果系统没有特殊和苛刻的性能要求,可以采用JVM的缺省选项。(4)关键的也是难把握的问题是内存泄漏。良好的编程习惯和严谨的编程态度永远是最重要的,(5)尽早释放无用对象的引用。大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为null,暗示垃圾收集器来收集该对象,还必须注意该引用的对象是否被监听,如果有,则要去掉监听器,然后再赋空值。结束语一般来说,Java开发人员可以不重视JVM中堆内存的分配和垃圾处理收集,但是,充分理解Java的这一特性可以让我们更有效地利用资源。同时要注意finalize()方法是Java的缺省机制,有时为确保对象资源的明确释放,可以编写自己的finalize方法。