上圖中obj1,obj2,obj3,obj4可達,obj5,obj6不可達(可被GC回收)。 html
1. 虛擬機棧中局部變量引用的對象。 java
2. 類靜態屬性引用的對象。 算法
3. 常量引用的對象。 緩存
4. JNI中引用的對象。 多線程
java中有四種引用類型(由強到弱): 併發
1. 廢棄常量(如無引用的常量字符串)。 oracle
2. 無用的類。 jvm
1. 該類的全部實例已經被回收。 jsp
2. 加載該類的ClassLoader已經被回收。 spa
3. 該類的java.lang.Class對象沒有被引用,沒法任何地方經過反射訪問該類。
簡單方便,內存碎片化嚴重
無內存碎片化, 浪費可用內存
無內存碎片化,充分利用可用內存
根據對象存活特性,合理使用不一樣回收算法,商業JVM都使用該回收算法。
1. 初始標記:標記GC Roots可關聯的對象,會暫停用戶線程。
2. 併發標記:GC Roots Tracing過程,用戶線程並行。
3. 從新標記:從新標記因爲在併發標記過程當中用戶線程致使的對象狀態變化,會暫停用戶線程。
4. 併發清理:清理可回收對象,用戶線程並行。
這些收集器都一些可控參數,根據實際場景來調整,這裏是官方文檔:
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
內存分配回收實例:
/** * 內存分配回收 * -XX:+PrintGCDetails 打印GC信息 * -Xms12M 起始堆大小 * -Xmx12M 最大堆大小 * -Xmn6M 年輕代大小 * -XX:SurvivorRatio=6 Eden:S0:S1 = 4:1:1 * * jvm args: * -XX:+PrintGCDetails -Xms12M -Xmx12M -Xmn6M -XX:SurvivorRatio=4 */ public class MemoryAllocate { private static final int _1M = 1024*1024; public static void main(String[] args) { byte[] b1 = new byte[_1M]; // allocate 1M byte[] b2 = new byte[_1M*2]; // allocate 2M byte[] b3 = new byte[_1M]; // allocate 1M, 發生年輕代GC(Minor GC) } }gc信息以下:
1.Minor GC:發生在年輕代,速度快,頻繁。
2.Full GC/Major GC:發生在老年代, 通常也伴隨Minor GC, 速度通常比Minor GC慢10倍以上。
/** * PretenureSizeThreshold * -XX:+PrintGCDetails 打印GC信息 * -Xms12M 起始堆大小 * -Xmx12M 最大堆大小 * -Xmn6M 年輕代大小 * -XX:SurvivorRatio=6 Eden:S0:S1 = 4:1:1 * -XX:PretenureSizeThreshold 對象超過該值,直接進入老年代,單位B * -XX:UseParNewGC 使用UserParNew收集器 * jvm args: * -XX:UseParNewGC -XX:+PrintGCDetails -Xms12M -Xmx12M -Xmn6M -XX:SurvivorRatio=4 -XX:PretenureSizeThreshold=2097152 */ public class PretenureSizeThreshold { private static final int _1M = 1024*1024; public static void main(String[] args) { // 分配2M, 大於PretenureSizeThreshold, 直接進入老年代 byte[] b1 = new byte[_1M * 3]; } }
上面就基本介紹了jvm分配回收內存策略。
不吝指正。