-
如何判斷對象可回收
根據可達性分析算法來判斷一個對象是否可回收,可達則不可回收,否則可回收; 從GC Roots對象開始,有引用鏈,存活,沒有則可回收,屬於GC Roots類型對象如下: 1.方法中的 參數,局部變量,臨時變量 (關心---堆區回收) 2.靜態變量(關心---方法區回收) 3.字符串常量的引用 (關心---方法區回收) 4.本地方法(native JNI)引用的對象 5.被同步鎖持有的對象 (關心---堆區回收) class Test{ //靜態變量 private static Object c=new Object(); public void test(參數){ //局部變量,臨時變量 Object o=new Object(); } } 說明: 1.回收不僅僅是針對堆區,回收會分爲方法區回收和堆區回收 2.堆區回收一些對象 3.方法區回收字符串常量和類型信息和靜態變量
-
引用類型
強引用: 儘管發送oom,也不回收的對象 軟引用:內存不足情況下,會回收弱引用對象,內存依然不足,發生oom 弱引用:不管內存是否足夠,下一次發生GC都會回收調的對象 虛引用:忽略
-
分代收集算法(針對堆回收)
1.分代收集理論:實際開發當中,對象分爲兩種:絕大部分對象朝生夕死,少部分對象存活比較長。 基於這個理論,對堆劃分代,不同代採用不同回收策略,那就是不同代使用不同回收算法, 最大的提高了回收效率。 2.分代回收類型: 新生代收集:Minor GC (堆分區的年輕代) 老年代收集:Major GC (堆老年代) 混合收集:Mixed GC (堆新生代和部分老年代) 整堆收集:Full GC (整個堆和整個方法區) 3.基本回收算法 標記清除算法:在堆中標記出非存活對象,然後釋放掉;在堆中標記出存活對象,把剩下的釋放掉,可選擇的。 缺點:1.效率不穩定,看存活對象的多少,就要標記多少,內存大的情況下,效率極低 2.碎片化內存,就原地釋放,釋放完後內存不一定連續 標記複製算法:年輕代對象98%活不過第一輪垃圾回收,也就是98%的對象都是要回收的,把年輕代的堆內存 分爲兩半,每次只用一塊內存,垃圾回收時,直接把存活對象複製到另外一半內存,按順序 進行分配剩下存活的對象 優點:1.不存在內存碎片化的問題,效率也高 缺點:1.比較浪費內存(後面進行了優化,將年輕代劃分爲eden和兩個survivor,內存比例 爲8:1:1,也就是每次只會浪費10%的內存) 總結:年輕代對象的特點,大多數選用這種垃圾回收算法 標記整理算法: 將內存中存活的對象,直接移向內存的另外一端,然後擦除邊界以外的部分 優點:1.不存在碎片化問題相對標記清除算法 2.不需要浪費10%的額外空間相對於標記複製算法 總結:1.年輕代的特性,標記複製算法比較適合 2.老年代的特性,標記清算和標記整理算法比較適合;標記清除由於碎片化問題,分配內存成本較高 標記整理不存在碎片化問題,但是要移動內存,分配內存方便,但是移動內存成本高
-
常見分代垃圾收集器
年輕代: serial: 使用標記複製算法,gc線程與應用線程是串行化的,gc時候所有應用線程暫停,直到gc完成 (適合內存比較小的情況下,如果再內存大的情況下,gc停頓太長,很影響用戶體驗) parNew: 使用標記複製算法,gc線程與應用線程是串行化的,gc時候所有應用線程暫停,直到gc完成 但是這個是serial的多線程版本,多個gc線程進行工作 (適合內存比較大的情況下,因爲gc多個線程工作,回收快,停頓時間短) parallel Scavenge:使用標記複製算法,gc線程與應用線程是串行化的,gc時候所有應用線程暫停,直到gc完成 但是這個是serial的多線程版本,多個gc線程進行工作 (和parNew差不多,但是可以根據業務場景,可調整gc時間,讓吞吐量達到一定可控) 老年代: serial old:使用標記整理算法,gc線程與應用線程是串行化的,gc時候所有應用線程暫停,直到gc完成 parallel old:使用標記整理算法,gc線程與應用線程是串行化的,gc時候所有應用線程暫停,直到gc完成 但是這個是serial old的多線程版本,多個gc線程進行工作 cms:使用標記清除算法,gc線程可以和用戶線程並行,停頓時間短
-
JDK8默認垃圾收集器
設置jvm options:-XX:+PrintGCDetails -XX:+PrintGCTimeStamps Heap PSYoungGen total 76288K, used 5261K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000) eden space 65536K, 8% used [0x000000076ab00000,0x000000076b0234a8,0x000000076eb00000) from space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000) to space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000) ParOldGen total 175104K, used 0K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000) object space 175104K, 0% used [0x00000006c0000000,0x00000006c0000000,0x00000006cab00000) Metaspace used 2934K, capacity 4496K, committed 4864K, reserved 1056768K class space used 319K, capacity 388K, committed 512K, reserved 1048576K 總結:jdk8的情況下,使用的垃圾回收parallel Scavenge 和parallel old
-
內存分配策略(jdk默認 PSYoungGen ParOldGen)
1.優先分配到eden區,如果內存不夠,發生minor gc,存活對象超過survivor大小,多出的直接轉移到老年代 否則,交換到survivor,將空出來的eden內存分配給新進來的對象 2.大對象直接分配到老年代(-XX:PretenureSizeThreshold) 3. 根據對象的年齡進入老年代(-XX:MaxTenuringThreshold) 分配小例子: 代碼: //-Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:PretenureSizeThreshold=6291456 byte[] b1=new byte[_1M*4]; byte[] b2=new byte[_1M*2]; gc日誌分析: 1.一開始佔用2596k 2.創建了一個數組用了 4096 --->已經使用6692k,eden剩餘,1500k 3.創建一個數組用了 2048,---->eden需要內存6692+2048,明顯eden內存不夠,發生minor gc一次 ----->發現survivor只有1024k,而總存活對象爲6692k(擔保分配到老年代4104k, survivor分配840k,回收了1584k,eden區留了163k) ----->2048k對象經過gc就可以直接分配到eden了
gc日誌
-
jvm內存模型
常見面試題之jvm內存回收和分配策略
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.