java 內存結構、GC

一:內存結構

 

 

1:程序計數器:當前線程的執行字節碼的行號,記錄運行情況;

2:虛擬機棧:記錄當前線程的局部變量、操作數棧、方法出口等信息;

3:本地方法棧:保存本地方法的棧信息,與虛擬機棧的區別就是虛擬機棧保存java運行信息;

4:堆(分新生代,老年代):線程共享區域,存放對象實例對象,所有的java實例基本都在這裏,是gc的主要區域,又稱“GC堆”;

5:方法區(永久代):線程共享區域,保存已被虛擬機加載的類信息,常量,靜態變量等信息;

5.1:運行時常量池:方法區的一部分,存放編譯時期的字面量和符號引用。

 

二:GC機制

確定gc的規則之可達性分析:從用到的引用(GC ROOTS)出發:經過所有引用鏈遍歷,不能到達的對象就是可以gc的對象。

GC Roots:

  • 虛擬機棧的引用
  • 方法區中的靜態屬性引用
  • 方法區的常量引用
  • 本地方法中的引用

GC過程:未能經過可達性驗證的對象都會標記下來,篩選有必要執行finalize方法的對象放入F_QUEUE中,然後用一個線程執行,這裏的執行是僅僅觸發,並不保證能執行完全。然後對F-QUEUE中的對象進行第二次標記,逃脫的對象免遭GC;最後回收對象。

 

 

逃脫GC的例子:

package cn.wzy.ThreadScope.escape;

/**
 * @author wzy 不短不長八字剛好.
 * @since 2018/9/19 9:16
 */
public class Escape {
	static Escape escape = null;

	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		System.out.println("====gc====");
		escape = this;
	}

	public static void main(String[] args) throws InterruptedException {
		escape = new Escape();
		escape = null;
		System.gc();//執行上一個對象的finalize方法
		Thread.sleep(5000);
		if (escape != null) {
			System.out.println("====alive=====");
		} else {
			System.out.println("=====dead=====");
		}
		escape = null;
		System.gc();
		Thread.sleep(5000);
		if (escape != null) {
			System.out.println("====alive=====");
		} else {
			System.out.println("=====dead=====");
		}
	}
}

輸出:

        ====gc====
        ====alive=====
        =====dead=====

在執行finalize的時候發現當前對象本來是不可達的、失去聯繫的對象,執行之後變成了可達對象,那麼逃脫gc,因爲對象的finalize是隻執行一次,所以第二次未執行這個方法,未能逃過。

三:垃圾收集算法(分代收集):

1、標記-清除算法:標記之後,將標記過的對象所在區域清除。

2、複製-清除算法:分成兩塊相等的區域,gc時將存活對象複製到另外一邊,清除本塊區域;擴展成:一塊較大的eden和兩塊survivor小區域,gc的時候將兩塊用的放到另外一塊survivor上,清理其他兩塊,來回複製:當一塊survivor上存不下的時候,將拿老年代區域來做擔保。

 

 

3、標記-整理算法:將存活對象向前擠,然後清除最後一個對象以後的區域。

分代收集:新生代和老年代都在堆內存中,新生代中的對象在很多次gc結束後還存活就會升級到老年代。永久代指的是方法區中的常量對象(如字符串對象、類信息Class對象)。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章