常見面試題之jvm內存回收和分配策略

  • 如何判斷對象可回收

    根據可達性分析算法來判斷一個對象是否可回收,可達則不可回收,否則可回收;
    從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,內存比例
      			 爲811,也就是每次只會浪費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內存模型

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