jvm垃圾回收机制

Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都在重复的allocated,然后不停的~析构。于是,有人就提出,能不能写一段程序在实现这块功能,每次创建,释放控件的时候复用这段代码,而无需重复的书写呢?

1960 基于MITLisp首先提出了垃圾回收的概念,用于处理C语言等不停的析构操作,而这时Java还没有出世呢!所以实际上GC并不是Java的专利,GC的历史远远大于Java的历史!

那究竟GC为我们做了什么操作呢?

 

1、    哪些内存需要回收?

2、    什么时候回收?

3、    如何回收?

 

这时候有人就会疑惑了,既然GC已经为我们解决了这个矛盾,我们还需要学习GC么?当然当然是肯定的,那究竟什么时候我们还需要用到的呢?

 

1、    排查内存溢出

2、    排查内存泄漏

3、    性能调优,排查并发瓶颈

 

我们知道,GC主要处理的是对象的回收操作,那么什么时候会触发一个对象的回收的呢?

1、    对象没有引用

2、    作用域发生未捕获异常

3、    程序在作用域正常执行完毕

4、    程序执行了System.exit()

5、    程序发生意外终止(被杀进程等)

其实,我们最容易想到的就是当对象没有引用的时候会将这个对象标记为可回收对象,那么现在就有一个问题,是不是这个对象被赋值为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;

    }

}

 

程序的运行结果回事什么样子的呢?

我们来看这段代码

 

1、  System.out.println(FinalizedEscapeTestCase.caseForEscape);

2、  FinalizedEscapeTestCase.caseForEscape = newFinalizedEscapeTestCase();

3、  System.out.println(FinalizedEscapeTestCase.caseForEscape);

4、  FinalizedEscapeTestCase.caseForEscape=null;

5、  System.gc();

6、  Thread.sleep(100);

7、    System.out.println(FinalizedEscapeTestCase.caseForEscape);

 

1、    当程序执行第一行是,因为这个对象没有值,结果肯定是null

2、    程序第二行给该对象赋值为新开辟的一个对象

3、    第三行打印的时候,肯定是第二行对象的hash代码

4、    第四行将该对象重新置为null

5、    第五行触发GC

6、    为了保证GC能够顺利执行完毕,第六行等待100毫秒

7、    第七行打印对应的值,回事null么?一定会是null么?

我们来看一下对应的运行结果


jvm垃圾回收机制

 本例中打印了

GC的日志,让我们看的更清晰一点,我们很清晰的看出,最后一句打印的不是null,并且子啊之前,还出现了逃逸的字样。说明这个对象逃逸了,在垃圾回收之前逃逸了,我们再来看这个pojo的写法,就会发现,我们重写了方法finalize,而这个方法就相当于C++中的析构方法,在GC回收之前,会先调用一次这个方法,而这个方法又将this指针指向他自己,因此得以成功逃逸!可见,并不是这个对象被赋值为null之后就一定被标记为可回收,有可能会发生逃逸!

你可能感兴趣的:(java,jvm,垃圾回收机制)