第二部分-垃圾回收

應(yīng)用計(jì)數(shù)器法沒(méi)辦法規(guī)避循環(huán)引用,忽略它。。。

跟搜索算法root節(jié)點(diǎn):

  • 虛擬機(jī)棧,本地方法棧中引用的對(duì)象
  • 方法區(qū)引用的類靜態(tài)變量(java8后已經(jīng)屬于堆了) // TODO 待確認(rèn)
  • 方法區(qū)中的常量引用的對(duì)象(java8后已經(jīng)屬于堆了) // TODO 待確認(rèn)

java的強(qiáng)軟弱虛引用

  • 強(qiáng)引用不多說(shuō),jvm無(wú)論如何都不會(huì)回收有強(qiáng)引用的對(duì)象
  • 軟引用,內(nèi)存快溢出前會(huì)回收軟引用對(duì)象。(安卓端一些圖片緩存,全部放進(jìn)內(nèi)存又太大,從磁盤慢慢讀又太慢,那就用軟引用緩存)
  • 弱引用,不確定的時(shí)間回收,垃圾收集器發(fā)現(xiàn)弱引用對(duì)象就會(huì)回收它。WeakHashMap就是弱引用的map實(shí)現(xiàn),它的key是關(guān)聯(lián)到一個(gè)軟引用的,一旦key在外面不存在引用了,會(huì)被自動(dòng)清除??梢詫eferenceQuene傳入WeakHashmap的構(gòu)造方法(constructor)中,這樣,一旦這個(gè)弱引用指向的對(duì)象成為垃圾,這個(gè)弱引用將加入ReferenceQuene??磦€(gè)例子:
import java.util.HashMap;  
import java.util.Iterator;  
import java.util.Map;  
import java.util.WeakHashMap;  

public class Test {  
    public static void main(String[] args) throws Exception {  
        String a = new String("a");  
        String b = new String("b");  
        Map weakmap = new WeakHashMap();  
        Map map = new HashMap();  
        map.put(a, "aaa");  
        map.put(b, "bbb");  

          
        weakmap.put(a, "aaa");  
        weakmap.put(b, "bbb");  

        map.remove(a);  

        a=null;  
        b=null;  

        System.gc();  
        Iterator i = map.entrySet().iterator();  
        while (i.hasNext()) {  
            Map.Entry en = (Map.Entry)i.next();  
            System.out.println("map:"+en.getKey()+":"+en.getValue());  
        }  

        Iterator j = weakmap.entrySet().iterator();  
        while (j.hasNext()) {  
            Map.Entry en = (Map.Entry)j.next();  
            System.out.println("weakmap:"+en.getKey()+":"+en.getValue());  

        }  
    }  

      
}  

當(dāng)把a(bǔ)和b都置為null后,hashmap中也不存在對(duì)它的引用了(remove掉了),外邊a也被置null了,weakhashmap將會(huì)自動(dòng)移除a為key的記錄,b雖然被置為null了,但是new String("bbb")出來(lái)的對(duì)象在hashmap中還存在引用,所以不會(huì)被回收。
(弱引用最大的用處是,你需要用一個(gè)對(duì)象,但也只是用一用,不能影響它的垃圾回收,比如需要監(jiān)控虛擬機(jī)中某些對(duì)象的屬性值,如果直接用強(qiáng)引用獲取,那么被監(jiān)控的對(duì)象將不會(huì)被gc回收,此時(shí)弱引用就派上了用場(chǎng))

  • 虛引用,它唯一的作用就是跟ReferenceQueue一起使用,通知對(duì)象被回收。
import java.lang.ref.PhantomReference;  
import java.lang.ref.Reference;  
import java.lang.ref.ReferenceQueue;  
import java.lang.reflect.Field;  
  
public class Test {  
    public static boolean isRun = true;  
  
    @SuppressWarnings("static-access")  
    public static void main(String[] args) throws Exception {  
        String abc = new String("abc");  
        System.out.println(abc.getClass() + "@" + abc.hashCode());  
        final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();  
        new Thread() {  
            public void run() {  
                while (isRun) {  
                    Object obj = referenceQueue.poll();  
                    if (obj != null) {  
                        try {  
                            Field rereferent = Reference.class  
                                    .getDeclaredField("referent");  
                            rereferent.setAccessible(true);  
                            Object result = rereferent.get(obj);  
                            System.out.println("gc will collect:"  
                                    + result.getClass() + "@"  
                                    + result.hashCode() + "\t"  
                                    + (String) result);  
                        } catch (Exception e) {  
                            e.printStackTrace();  
                        }  
                    }  
                }  
            }  
        }.start();  
        PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,  
                referenceQueue);  
        abc = null;  
        Thread.currentThread().sleep(3000);  
        System.gc();  
        Thread.currentThread().sleep(3000);  
        isRun = false;  
    }  
}  


我們可以聲明虛引用來(lái)引用我們感興趣的對(duì)象,在gc要回收的時(shí)候,gc收集器會(huì)把這個(gè)對(duì)象添加到referenceQueue(如上例中,abcWeakRef虛引用就對(duì)abs這個(gè)對(duì)象感興趣,abc被回收時(shí)會(huì)被放入referenceQueue中,我們只用監(jiān)聽(tīng)referenceQueue就知道哪些對(duì)象被回收了),這樣我們?nèi)绻麢z測(cè)到referenceQueue中有我們感興趣的對(duì)象的時(shí)候,說(shuō)明gc將要回收這個(gè)對(duì)象了。此時(shí)我們可以在gc回收之前做一些其他事情(如安卓圖片滾動(dòng)顯示,每次只顯示一張圖片,但是圖片特別大,內(nèi)存只能容得下一張圖片的大小,此時(shí)就需要虛引用來(lái)監(jiān)聽(tīng)前一張圖片是否已經(jīng)被移除,移除之后才能加載下一張圖片進(jìn)來(lái))

finalize方法

沒(méi)有實(shí)現(xiàn)finallize方法的對(duì)象不會(huì)執(zhí)行這一堆邏輯,對(duì)象回收時(shí)干的事情,執(zhí)行后對(duì)象會(huì)被放入F-queue中,如果此時(shí)對(duì)象又被引用上,對(duì)象將起死回生。每個(gè)對(duì)象虛擬機(jī)只會(huì)執(zhí)行一次finalize方法。建議對(duì)象回收監(jiān)聽(tīng)使用虛引用(幽靈引用)來(lái)實(shí)現(xiàn)。

回收方法區(qū)

  • 回收常量池

某個(gè)字符串已經(jīng)沒(méi)有任何引用指向它時(shí)即可回收。

  • 回收類條件
  1. 沒(méi)有任何類實(shí)例(全部被回收)
  2. 加載該類的類加載器已經(jīng)被回收
  3. 類的Class對(duì)象沒(méi)有在任何地方被引用(不能反射創(chuàng)建實(shí)例)

類回收相關(guān)虛擬機(jī)參數(shù):

  • -verbose:class可以查看類加載信息
  • -XX:+TraceClassLoading,-XX:+TraceClassUnLoading可以查看類的加載和卸載信息。

垃圾收集算法

  • 標(biāo)記清除
  • 復(fù)制
  • 標(biāo)記整理
  • 分代收集

垃圾收集器

  • Seria收集器(串行收集器,單線程,采用復(fù)制算法)年輕代收集器

  • ParNew(和Seria一樣,只是多線程版本而已)年輕帶收集器

  • SeriaOld 串行收集器,老年代版本,但是使用標(biāo)記整理算法。

  • CMS并發(fā)老年代收集器。(標(biāo)記清除)
    初始標(biāo)記,并發(fā)標(biāo)記,重新標(biāo)記,并發(fā)清除。

  • G1收集器:http://blog.csdn.net/renfufei/article/details/41897113 待學(xué)習(xí)

內(nèi)存分配回收策略

  • 優(yōu)先分配到eden區(qū)域

參數(shù):-Xms20M -Xmx20M 堆最小值及最大值,-Xmn10M堆的新生代大小,設(shè)置為10MB后,老年代大小就為20m-10m=10m了。 -XX:SurvivorRatio=8代表survicor:eden=1:8,設(shè)置為8后,新生代中eden區(qū)域就占8/10,兩個(gè)survivor分別占1/10;

  • 大對(duì)象(大數(shù)組或超長(zhǎng)字符串)直接進(jìn)入老年代

因?yàn)閷?duì)象太大先存入eden區(qū),再進(jìn)survivor進(jìn)行復(fù)制算法拷貝代價(jià)就會(huì)比較大。
可以使用虛擬機(jī)參數(shù)-XX:PretenureSzieThreshold:13723來(lái)設(shè)定判斷大對(duì)象的閾值(需要注意,這里單位默認(rèn)為b,寫的時(shí)候不能自定義單位,另外,只有parNew和Seria收集器會(huì)識(shí)別該參數(shù))

  • 長(zhǎng)期存活對(duì)象進(jìn)入老年代

并發(fā)那一塊的筆記里對(duì)對(duì)象頭的介紹,除了偏向鎖等信息等之外就有一個(gè)age屬性,記錄對(duì)象的垃圾收集年齡,在survivor區(qū)每次被復(fù)制都會(huì)+1,虛擬機(jī)默認(rèn)達(dá)到15歲進(jìn)入老年代,可以手動(dòng)設(shè)置年齡閾值,-XX:MaxTenuringThreshold:5

tips:虛擬機(jī)有另外一個(gè)動(dòng)態(tài)年齡判斷規(guī)則,如果某個(gè)年齡的對(duì)象大小占據(jù)了survivor區(qū)的一半,則會(huì)將年齡大于等于該年齡的所有對(duì)象晉升到老年區(qū)。

  • 空間分配擔(dān)保

擔(dān)保,就是年輕代沒(méi)有容納能力了,老年代替你存。(這里老年代替年輕代存的是新的需要分配空間的對(duì)象還是survivor區(qū)的最老的對(duì)象??????。。』卮?當(dāng)然是最老的對(duì)象了咯,除非是大對(duì)象)
?。】臻g分配擔(dān)保是一直都開(kāi)啟的,HandlePromotionFailure參數(shù)只是設(shè)置是否允許擔(dān)保失敗。

HandlePromotionFailure參數(shù)配置的影響:每次minorgc前先判斷老年代是否能容納全部當(dāng)前年輕代的大小,成立->直接minorgc即可,不成立-> (老年代剩余空間小于平均晉升大小 || 不允許擔(dān)保失敗 -> fullgc , else -> minorgc)

結(jié)論:

  1. HandlePromotionFailure設(shè)置成了false,每次minorgc時(shí)只要老年代容不下所有年輕代了,都會(huì)被改為fullgc??!
  2. 設(shè)置為true后,只有靠平均晉升大小來(lái)判斷是否觸發(fā)fullgc了,這樣的經(jīng)驗(yàn)判斷,肯定會(huì)有失誤的時(shí)候,一旦某次晉升對(duì)象大小大于經(jīng)驗(yàn)值,此時(shí)會(huì)再觸發(fā)一次fullgc
  3. 所以,一般都會(huì)將HandlePromotionFailure設(shè)置為true,不要讓虛擬機(jī)頻繁的fullgc
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 來(lái)自: Android夢(mèng)想特工隊(duì)作者: Aaron主頁(yè): http://www.wxtlife.com/原...
    技術(shù)特工隊(duì)閱讀 4,409評(píng)論 0 28
  • 注意 : 本系列文章為學(xué)習(xí)系列,部分內(nèi)容會(huì)取自相關(guān)書籍或者網(wǎng)絡(luò)資源,在文章中間和末尾處會(huì)有標(biāo)注 垃圾回收的意義 它...
    lyk2112閱讀 338評(píng)論 0 0
  • 作者:一字馬胡 轉(zhuǎn)載標(biāo)志 【2017-11-12】 更新日志 日期更新內(nèi)容備注 2017-11-12新建文章初版 ...
    beneke閱讀 2,235評(píng)論 0 7
  • 1.什么是垃圾回收? 垃圾回收(Garbage Collection)是Java虛擬機(jī)(JVM)垃圾回收器提供...
    簡(jiǎn)欲明心閱讀 89,862評(píng)論 17 311
  • JVM內(nèi)存區(qū)域 JVM將其管理的內(nèi)存分為若干數(shù)據(jù)區(qū)域,這些數(shù)據(jù)區(qū)域分布情況如下圖所示: 程序計(jì)數(shù)器:一塊較小內(nèi)存區(qū)...
    luoxn28閱讀 712評(píng)論 0 0