Java语言出来以前,你们都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言建立对象要不断的去开辟空间,不用的时候有须要不断的去释放控件,既要写构造函数,又要写析构函数,不少时候都在重复的allocated,而后不停的~析构。因而,有人就提出,能不能写一段程序在实现这块功能,每次建立,释放控件的时候复用这段代码,而无需重复的书写呢?java
1960年 基于MIT的Lisp首先提出了垃圾回收的概念,用于处理C语言等不停的析构操做,而这时Java尚未出世呢!因此实际上GC并非Java的专利,GC的历史远远大于Java的历史!并发
那究竟GC为咱们作了什么操做呢?jvm
一、 哪些内存须要回收?ide 二、 何时回收?函数 三、 如何回收?性能 |
这时候有人就会疑惑了,既然GC已经为咱们解决了这个矛盾,咱们还须要学习GC么?固然固然是确定的,那究竟何时咱们还须要用到的呢?学习
一、 排查内存溢出测试 二、 排查内存泄漏this 三、 性能调优,排查并发瓶颈spa |
咱们知道,GC主要处理的是对象的回收操做,那么何时会触发一个对象的回收的呢?
一、 对象没有引用
二、 做用域发生未捕获异常
三、 程序在做用域正常执行完毕
四、 程序执行了System.exit()
五、 程序发生意外终止(被杀进程等)
其实,咱们最容易想到的就是当对象没有引用的时候会将这个对象标记为可回收对象,那么如今就有一个问题,是否是这个对象被赋值为null之后就必定被标记为可回收对象了呢?咱们来看一个例子:
package com.yhj.jvm.gc.objEscape.finalizeEscape;
import com.yhj.jvm.gc.objEscape.pojo.FinalizedEscapeTestCase;
/** * @Described:逃逸分析测试 * @author YHJ create at 2011-12-24 下午05:08:09 * @FileNmae com.yhj.jvm.gc.finalizeEscape.FinalizedEscape.java */ public class FinalizedEscape { public static void main(String[] args) throwsInterruptedException { System.out.println(FinalizedEscapeTestCase.caseForEscape); FinalizedEscapeTestCase.caseForEscape = newFinalizedEscapeTestCase(); System.out.println(FinalizedEscapeTestCase.caseForEscape); FinalizedEscapeTestCase.caseForEscape=null; System.gc(); Thread.sleep(100); System.out.println(FinalizedEscapeTestCase.caseForEscape); } } package com.yhj.jvm.gc.objEscape.pojo; /** * @Described:逃逸分析测试用例 * @author YHJ create at 2011-12-24 下午05:07:05 * @FileNmae com.yhj.jvm.gc.pojo.TestCaseForEscape.java */ public class FinalizedEscapeTestCase {
public static FinalizedEscapeTestCase caseForEscape = null; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("哈哈,我已逃逸!"); caseForEscape = this; } } |
程序的运行结果回事什么样子的呢?
咱们来看这段代码
一、 System.out.println(FinalizedEscapeTestCase.caseForEscape); 二、 FinalizedEscapeTestCase.caseForEscape = newFinalizedEscapeTestCase(); 三、 System.out.println(FinalizedEscapeTestCase.caseForEscape); 四、 FinalizedEscapeTestCase.caseForEscape=null; 五、 System.gc(); 六、 Thread.sleep(100); 七、 System.out.println(FinalizedEscapeTestCase.caseForEscape); |
一、 当程序执行第一行是,由于这个对象没有值,结果确定是null
二、 程序第二行给该对象赋值为新开辟的一个对象
三、 第三行打印的时候,确定是第二行对象的hash代码
四、 第四行将该对象从新置为null
五、 第五行触发GC
六、 为了保证GC可以顺利执行完毕,第六行等待100毫秒
七、 第七行打印对应的值,回事null么?必定会是null么?
咱们来看一下对应的运行结果
本例中打印了
GC的日志,让咱们看的更清晰一点,咱们很清晰的看出,最后一句打印的不是null,而且子啊以前,还出现了逃逸的字样。说明这个对象逃逸了,在垃圾回收以前逃逸了,咱们再来看这个pojo的写法,就会发现,咱们重写了方法finalize,而这个方法就至关于C++中的析构方法,在GC回收以前,会先调用一次这个方法,而这个方法又将this指针指向他本身,所以得以成功逃逸!可见,并非这个对象被赋值为null以后就必定被标记为可回收,有可能会发生逃逸!