1. 程式人生 > >認識java虛擬機器(3)

認識java虛擬機器(3)

記憶體分配策略:

優先分配到eden

大物件直接分配到老年代

長期存活的物件分配到老年代

空間分配擔保

動態物件年齡判斷

 

1.優先分配到eden

-verbose:gc -XX:+PrintGCDetails  預設是Parallel Scavenge 收集器,標誌為:PSYoungGen

-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC   指定Serial收集器  ,標誌為:def new generation

 

public class Main {
	
	public static void main(String[] args) {
		byte [] m=new byte[4*1024*1024];
	}
}

程式碼中為byte陣列分配了4M的空間,執行結果:大致分析

    新生代總計記憶體33M,使用了6M,eden區域 記憶體總計30M,21%的空間被使用,tenured generation養老區記憶體總計75M

更改程式碼如下:

public class Main {
	
	public static void main(String[] args) {
		byte [] m=new byte[40*1024*1024];
	}
}

執行發現:大物件被直接分配到了tenured generation,eden區域的使用記憶體減少

指定jvm引數:

-verbose:gc(-verbose:gc 是 -XX:+PrintGC的別名,列印gc執行資訊)

-XX:+PrintGCDetails(詳細列印jvm執行日誌)

-XX:+UseSerialGC(指定serial GC垃圾回收器)

-Xms20M(設定JVM最大可用記憶體為20M)

-Xmx20M(用來設定程式初始化的時候記憶體棧的大小,增加這個值的話你的程式的啟動效能會得到提高

                     此值可以設定與-Xmx相同,以避免每次垃圾回收完成後JVM重新分配記憶體)

-Xmn10M(指定新生代記憶體10M)

-XX:SurvivorRatio=8 (指定新生代的eden為8M)

-XX:PretenureSizeThreshold=6M(指定6M以上的就判定為大物件,大物件直接分配到tenured區)

public class Main {
	
	public static void main(String[] args) {
		//m1,m2,m3被分配到了tenured區域 8.192M*58%=4M
		byte [] m1=new byte[2*1024*1024];
		byte [] m2=new byte[2*1024*1024];
		byte [] m3=new byte[2*1024*1024];
		//m4被分配到了eden區,10M*60%=6M
		byte [] m4=new byte[4*1024*1024];
		//呼叫gc垃圾回收,回收from space和to   space 垃圾區域所佔的記憶體
		System.gc();
	}
}

[GC (Allocation Failure) [DefNew: 7129K->530K(9216K),] 7129K->6674K(19456K), 


<p>呼叫allocation gc,回收了eden的7M空間,6M的三個物件仍存活,故未被清理掉</p>

[Full GC (System.gc()) [Tenured: 6144K->6144K(10240K)] 10930K->10768K(19456K), [Metaspace: 2654K->2654K(1056768K)]

<h1>呼叫full gc,清理掉from space的1M垃圾空間</h1>
Heap
 def new generation   total 9216K, used 4788K
  eden space 8192K,  58% used 
  from space 1024K,   0% used 
  to   space 1024K,   0% used 
 tenured generation   total 10240K, used 6144K 
   the space 10240K,  60% used
 Metaspace       used 2660K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 286K, capacity 386K, committed 512K, reserved 1048576K

長期存活的物件進入老年代

-XX:MaxTenuringThreshold 15

Age 1+1+1

 

空間分配擔保:

-XX:+HandlePromotionFailure(先衡量有無足夠的能力【空間】滿足你的記憶體分配的需求,+是開啟,-是禁用,老年代的空間並不能容納下所有的新生代的物件的空間)

 

逃逸分析與棧上分配

棧上分配:方法執行需要建立一個棧幀,方法執行,棧幀進棧出棧,棧區域是根據方法的執行來進行分配與釋放,不需要垃圾回收器來處理,效能很高

為逃逸的物件的可在棧上進行分配,分析出物件的作用域(方法體內部,方法內有效,它為逃逸,故可分配在棧上)

 

逃逸分析的情況:

public class StackAllocation {
	 public StackAllocation obj;
	/* 方法返回StackAllocation物件,放生逃逸*/
    public StackAllocation getInstance() {
    	return obj==null?new StackAllocation():obj;
    }
	/* 為成員屬性賦值,放生逃逸*/
	 public void setObj() {
		 this.obj=new StackAllocation();
	 }
	 
	/* 物件的作用域僅在當前方法中有效,沒有發生逃逸*/
	 public void useStackAllcation() {
		 /*在方法中定義物件,則物件會被直接分配到棧中,隨著方法結束,棧記憶體就會被移出,記憶體回收,物件也隨之銷燬,效能較高
		 能區域性建立物件,就區域性建立物件*/
		 StackAllocation s =new StackAllocation();
	 }
	/* 引用成員變數的值,發生逃逸*/
	 public void useStackAllocation2() {
		 StackAllocation s=getInstance();
	 }
}