Java gc(垃圾回收機制)小結,以及Android優化建議

若是本文幫助到你,本人不勝榮幸,若是浪費了你的時間,本人深感抱歉。 但願用最簡單的大白話來幫助那些像我同樣的人。若是有什麼錯誤,請必定指出,以避免誤導你們、也誤導我。 本文來自:www.jianshu.com/users/320f9… 感謝您的關注。html

Java的內存是不用咱們開發者本身來管理的,這個你們都知道,可是那它究竟是怎麼運做的呢? 咱們都知道GC,也就是垃圾回收機制,但到底什麼是GC。 咱們一塊兒來看看。java

什麼是GC

垃圾回收是一種自動的存儲管理機制。當一些被佔用的內存再也不須要時,就應該予以釋放,以讓出空間,這種存儲資源管理,稱爲垃圾回收(garbage collection)。垃圾回收器可讓程序員減輕許多負擔,也減小程序員犯錯的機會。 咱們來主要看看Java的gc機制。程序員

整個Java堆能夠切割成爲三個部分:算法

  1. Young(年輕代):
    1. Eden(伊利園):存放新生對象。
    2. Survivor(倖存者):存放通過垃圾回收沒有被清除的對象。
  2. Tenured(老年代):對象屢次回收沒有被清除,則移到該區塊。
  3. Perm:存放加載的類別還有方法對象。

GC會形成什麼影響

在開始學習GC以前你應該知道一個詞:stop-the-world。無論選擇哪一種GC算法,stop-the-world都是不可避免的。 也就是說,當垃圾回收開始清理資源時,其他的全部線程都會被中止。因此,咱們要作的就是儘量的讓它執行的時間變短。若是清理的時間過長,在咱們的應用程序中就能感受到明顯的卡頓。數組

什麼狀況下GC會執行

由於它對系統影響很明顯,因此它到底在何時執行呢?緩存

總的來講,有兩個條件會觸發主GC:性能優化

  1. 當應用程序空閒時,即沒有應用線程在運行時,GC會被調用。由於GC在優先級最低的線程中進行,因此當應用忙時,GC線程就不會被調用,但如下條件除外。
  2. Java堆內存不足時,GC會被調用。當應用線程在運行,並在運行過程當中建立新對象,若這時內存空間不足,JVM就會強制地調用GC線程,以便回收內存用於新的分配。若GC一次以後仍不能知足內存分配的要求,JVM會再進行兩次GC做進一步的嘗試,若仍沒法知足要求,則 JVM將報「out of memory」的錯誤,Java應用將中止。

因爲是否進行主GC由JVM根據系統環境決定,而系統環境在不斷的變化當中,因此主GC的運行具備不肯定性,沒法預計它什麼時候必然出現,但能夠肯定的是對一個長期運行的應用來講,其主GC是反覆進行的。數據結構

垃圾回收的通常步驟

以前已經瞭解到Java堆被主要分紅三個部分,而垃圾回收主要是在Young(年輕代)和Tenured(老年代)工做。 而 年輕代 又包括 Eden(伊利園)和兩個Survivor(倖存者)。 下面咱們就來看看這些空間是如何進行交互的:函數

一、首先,全部新生成的對象都是放在年輕代的Eden分區的,初始狀態下兩個Survivor分區都是空的。年輕代的目標就是儘量快速的收集掉那些生命週期短的對象。性能

二、當Eden區滿的的時候,小垃圾收集就會被觸發。

三、當Eden分區進行清理的時候,會把引用對象移動到第一個Survivor分區,無引用的對象刪除。

四、在下一個小垃圾收集的時候,在Eden分區中會發生一樣的事情:無引用的對象被刪除,引用對象被移動到另一個Survivor分區(S1)。此外,從上次小垃圾收集過程當中第一個Survivor分區(S0)移動過來的對象年齡增長,而後被移動到S1。當全部的倖存對象移動到S1之後,S0和Eden區都會被清理。注意到,此時的Survivor分區存儲有不一樣年齡的對象。

五、在下一個小垃圾收集,一樣的過程反覆進行。然而,此時Survivor分區的角色發生了互換,引用對象被移動到S0,倖存對象年齡增大。Eden和S1被清理。

六、這幅圖展現了從年輕代到老年代的提高。當進行一個小垃圾收集以後,若是此時年老對象此時到達了某一個個年齡閾值(例子中使用的是8),JVM會把他們從年輕代提高到老年代。

七、隨着小垃圾收集的持續進行,對象將會被持續提高到老年代。

八、這樣幾乎涵蓋了年輕一代的整個過程。最終,在老年代將會進行大垃圾收集,這種收集方式會清理-壓縮老年代空間。


也就是說,剛開始會先在新生代內部反覆的清理,頑強不死的移到老生代清理,最後都清不出空間,就爆炸了。

與堆配置相關的參數

參數 描述
-Xms JVM啓動的時候設置初始堆的大小
-Xmx 設置最大堆的大小
-Xmn 設置年輕代的大小
-XX:PermSize 設置持久代的初始的大小
-XX:MaxPermSize 設置持久代的最大值

優化建議:

根據GC的工做原理,咱們能夠經過一些技巧和方式,讓GC運行更加有效率

  1. 最基本的建議就是儘早釋放無用對象的引用。大多數程序員在使用臨時變量的時候,都是讓引用變量在退出活動域(scope)後,自動設置爲 null。好的作法是:若是程序容許,儘早將不用的引用對象賦爲null,這樣能夠加速GC的工做;
  2. 儘可能少用finalize函數。finalize函數是Java提供給程序員一個釋放對象或資源的機會。可是,它會加大GC的工做量,所以儘可能少採用finalize方式回收資源;
  3. 若是須要使用常用的圖片,可使用SoftReference類型。它能夠儘量將圖片保存在內存中,供程序調用,而不引發OutOfMemory;
  4. 注意集合數據類型,包括數組,樹,圖,鏈表等數據結構,這些數據結構對GC來講,回收更爲複雜,因此使用結束應當即置爲null,不要等堆在一塊兒。另外,注意一些全局的變量,以及一些靜態變量。這些變量每每容易引發懸掛對象(dangling reference),形成內存浪費;
  5. 當程序有必定的等待時間(注意,是有必定等待時間時),程序員能夠手動執行System.gc(),通知GC運行,可是Java語言規範並不保證GC必定會執行。使用增量式GC能夠縮短Java程序的暫停時間。System.gc(); Runtime.getRuntime().gc() 這個方法對資源消耗較大盡可能不要手動去調用這個方法,否則可能引發程序的明顯卡頓
  6. 儘可能使用StringBuffer,而不用String來累加字符串
  7. 能用基本類型如int,long,就不用Integer,Long對象。基本類型變量佔用的內存資源比相應對象佔用的少得多;
  8. 儘可能少用靜態對象變量,靜態變量屬於全局變量,不會被GC回收,它們會一直佔用內存;
  9. 分散對象建立或刪除的時間,集中在短期內大量建立新對象,特別是大對象,會致使忽然須要大量內存,JVM在面臨這種狀況時,只能進行主GC,以回收內存或整合內存碎片,從而增長主GC的頻率。

合理使用 軟引用 和 弱引用

清除 將引用對象的 referent 域設置爲 null ,並將引用類在堆中引用的對象聲明爲 可結束的。 StrongReference 強引用:正常的對象,一直不會清理,直到爆炸。 SoftReference 軟引用:內存不夠的時候,遇到了就清了。 WeakReference 弱引用:只要遇到了就清了,注意:可能清了好幾回,都沒遇到。 PhantomReference 虛引用:虛顧名思義就是沒有的意思,創建虛引用以後經過get方法返回結果始終爲null。

PhantomReference 必須與 ReferenceQueue 類一塊兒使用。須要 ReferenceQueue 是由於它可以充當通知機制。當垃圾收集器肯定了某個對象是虛可及對象時, PhantomReference 對象就被放在它的 ReferenceQueue 上。將 PhantomReference 對象放在 ReferenceQueue 上也就是一個通知,代表 PhantomReference 對象引用的對象已經結束,可供收集了。這使您可以恰好在對象佔用的內存被回收以前採起行動。

給個軟引用的例子:

//首先定義一個HashMap,保存軟引用對象。
private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
 
//再來定義一個方法,保存Bitmap的軟引用到HashMap。
public void addBitmapToCache(String path) {
    // 強引用的Bitmap對象
    Bitmap bitmap = BitmapFactory.decodeFile(path);
    // 軟引用的Bitmap對象
    SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
    // 添加該對象到Map中使其緩存
    imageCache.put(path, softBitmap);
}


//獲取的時候,能夠經過SoftReference的get()方法獲得Bitmap對象。
public Bitmap getBitmapByPath(String path) {
    // 從緩存中取軟引用的Bitmap對象
    SoftReference<Bitmap> softBitmap = imageCache.get(path);
    // 判斷是否存在軟引用
    if (softBitmap == null) {
        return null;
    }
    // 取出Bitmap對象,若是因爲內存不足Bitmap被回收,將取得空
    Bitmap bitmap = softBitmap.get();
    return bitmap;
}
複製代碼

參考及學習連接:

www.cnblogs.com/shudonghe/p… Java 垃圾回收機制技術詳解 blog.csdn.net/lu100528736… Java 垃圾回收機制 (GC) 詳解、意義、建議 blog.csdn.net/ithomer/art… Java 內存模型及GC原理 www.codeceo.com/article/jav… Java GC專家系列1:理解Java垃圾回收 www.codeceo.com/article/jav… Java GC專家系列2:Java 垃圾回收的監控 www.codeceo.com/article/jav… Java GC 專家系列3:GC調優實踐

Android性能優化-內存泄漏的8個Case

blog.csdn.net/huoyin/arti… Java中三個引用類SoftReference 、 WeakReference 和 PhantomReference的區別

相關文章
相關標籤/搜索