jvm垃圾回收機制

Java語言出來以前,你們都在拼命的寫C或者C++的程序,而此時存在一個很大的矛盾,C++等語言建立對象要不斷的去開闢空間,不用的時候有須要不斷的去釋放控件,既要寫構造函數,又要寫析構函數,不少時候都在重複的allocated,而後不停的~析構。因而,有人就提出,能不能寫一段程序在實現這塊功能,每次建立,釋放控件的時候複用這段代碼,而無需重複的書寫呢?java

1960 基於MITLisp首先提出了垃圾回收的概念,用於處理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以後就必定被標記爲可回收,有可能會發生逃逸!

相關文章
相關標籤/搜索