Java gc(垃圾回收機制)小結,以及Android優化建議
Java gc(垃圾回收機制)小結,以及Android優化建議
如果本文幫助到你,本人不勝榮幸,如果浪費了你的時間,本人深感抱歉。
希望用最簡單的大白話來幫助那些像我一樣的人。如果有什麼錯誤,請一定指出,以免誤導大家、也誤導我。
本文來自:http://www.jianshu.com/users/320f9e8f7fc9/latest_articles
感謝您的關注。
Java的記憶體是不用我們開發者自己來管理的,這個大家都知道,但是那它到底是怎麼運作的呢?
我們都知道GC,也就是垃圾回收機制,但到底什麼是GC。
我們一起來看看。
什麼是GC
垃圾回收是一種自動的儲存管理機制。當一些被佔用的記憶體不再需要時,就應該予以釋放,以讓出空間,這種儲存資源管理,稱為垃圾回收(garbage collection)。垃圾回收器可以讓程式設計師減輕許多負擔,也減少程式設計師犯錯的機會。
整個Java堆可以切割成為三個部分:
Young(年輕代):
Eden(伊利園):存放新生物件。
Survivor(倖存者):存放經過垃圾回收沒有被清除的物件。
Tenured(老年代):物件多次回收沒有被清除,則移到該區塊。
Perm:存放載入的類別還有方法物件。
GC會造成什麼影響
在開始學習GC之前你應該知道一個詞:stop-the-world。不管選擇哪種GC演算法,stop-the-world都是不可避免的。
也就是說,當垃圾回收開始清理資源時,其餘的所有執行緒都會被停止。所以,我們要做的就是儘可能的讓它執行的時間變短。如果清理的時間過長,在我們的應用程式中就能感覺到明顯的卡頓。
什麼情況下GC會執行
因為它對系統影響很明顯,所以它到底在什麼時候執行呢?
總的來說,有兩個條件會觸發主GC:
當應用程式空閒時,即沒有應用執行緒在執行時,GC會被呼叫。因為GC在優先順序最低的執行緒中進行,所以當應用忙時,GC執行緒就不會被呼叫,但以下條件除外。
Java堆記憶體不足時,GC會被呼叫。當應用執行緒在執行,並在執行過程中建立新物件,若這時記憶體空間不足,JVM就會強制地呼叫GC執行緒,以便回收記憶體用於新的分配。若GC一次之後仍不能滿足記憶體分配的要求,JVM會再進行兩次GC作進一步的嘗試,若仍無法滿足要求,則 JVM將報“out of memory”的錯誤,Java應用將停止。
垃圾回收的一般步驟
之前已經瞭解到Java堆被主要分成三個部分,而垃圾回收主要是在Young(年輕代)和Tenured(老年代)工作。
而 年輕代 又包括 Eden(伊利園)和兩個Survivor(倖存者)。
下面我們就來看看這些空間是如何進行互動的:
1、首先,所有新生成的物件都是放在年輕代的Eden分割槽的,初始狀態下兩個Survivor分割槽都是空的。年輕代的目標就是儘可能快速的收集掉那些生命週期短的物件。
2、當Eden區滿的的時候,小垃圾收集就會被觸發。
3、當Eden分割槽進行清理的時候,會把引用物件移動到第一個Survivor分割槽,無引用的物件刪除。
4、在下一個小垃圾收集的時候,在Eden分割槽中會發生同樣的事情:無引用的物件被刪除,引用物件被移動到另外一個Survivor分割槽(S1)。此外,從上次小垃圾收集過程中第一個Survivor分割槽(S0)移動過來的物件年齡增加,然後被移動到S1。當所有的倖存物件移動到S1以後,S0和Eden區都會被清理。注意到,此時的Survivor分割槽儲存有不同年齡的物件。
5、在下一個小垃圾收集,同樣的過程反覆進行。然而,此時Survivor分割槽的角色發生了互換,引用物件被移動到S0,倖存物件年齡增大。Eden和S1被清理。
6、這幅圖展示了從年輕代到老年代的提升。當進行一個小垃圾收集之後,如果此時年老物件此時到達了某一個個年齡閾值(例子中使用的是8),JVM會把他們從年輕代提升到老年代。
7、隨著小垃圾收集的持續進行,物件將會被持續提升到老年代。
8、這樣幾乎涵蓋了年輕一代的整個過程。最終,在老年代將會進行大垃圾收集,這種收集方式會清理-壓縮老年代空間。
也就是說,剛開始會先在新生代內部反覆的清理,頑強不死的移到老生代清理,最後都清不出空間,就爆炸了。
與堆配置相關的引數
引數 描述
-Xms JVM啟動的時候設定初始堆的大小
-Xmx 設定最大堆的大小
-Xmn 設定年輕代的大小
-XX:PermSize 設定持久代的初始的大小
-XX:MaxPermSize 設定持久代的最大值
優化建議:
根據GC的工作原理,我們可以通過一些技巧和方式,讓GC執行更加有效率
最基本的建議就是儘早釋放無用物件的引用。大多數程式設計師在使用臨時變數的時候,都是讓引用變數在退出活動域(scope)後,自動設定為 null。好的做法是:如果程式允許,儘早將不用的引用物件賦為null,這樣可以加速GC的工作;
儘量少用finalize函式。finalize函式是Java提供給程式設計師一個釋放物件或資源的機會。但是,它會加大GC的工作量,因此儘量少採用finalize方式回收資源;
如果需要使用經常使用的圖片,可以使用SoftReference型別。它可以儘可能將圖片儲存在記憶體中,供程式呼叫,而不引起OutOfMemory;
注意集合資料型別,包括陣列,樹,圖,連結串列等資料結構,這些資料結構對GC來說,回收更為複雜,所以使用結束應立即置為null,不要等堆在一起。另外,注意一些全域性的變數,以及一些靜態變數。這些變數往往容易引起懸掛物件(dangling reference),造成記憶體浪費;
當程式有一定的等待時間(注意,是有一定等待時間時),程式設計師可以手動執行System.gc(),通知GC執行,但是Java語言規範並不保證GC一定會執行。使用增量式GC可以縮短Java程式的暫停時間。System.gc(); Runtime.getRuntime().gc() 這個方法對資源消耗較大盡量不要手動去呼叫這個方法,不然可能引起程式的明顯示卡頓;
儘量使用StringBuffer,而不用String來累加字串
能用基本型別如int,long,就不用Integer,Long物件。基本型別變數佔用的記憶體資源比相應物件佔用的少得多;
儘量少用靜態物件變數,靜態變數屬於全域性變數,不會被GC回收,它們會一直佔用記憶體;
分散物件建立或刪除的時間,集中在短時間內大量建立新物件,特別是大物件,會導致突然需要大量記憶體,JVM在面臨這種情況時,只能進行主GC,以回收記憶體或整合記憶體碎片,從而增加主GC的頻率。
合理使用 軟引用 和 弱引用
清除 將引用物件的 referent 域設定為 null ,並將引用類在堆中引用的物件宣告為 可結束的。
StrongReference 強引用:正常的物件,一直不會清理,直到爆炸。
SoftReference 軟引用:記憶體不夠的時候,遇到了就清了。
WeakReference 弱引用:只要遇到了就清了,注意:可能清了好幾次,都沒遇到。
PhantomReference 虛引用:虛顧名思義就是沒有的意思,建立虛引用之後通過get方法返回結果始終為null。
PhantomReference 必須與 ReferenceQueue 類一起使用。需要 ReferenceQueue 是因為它能夠充當通知機制。當垃圾收集器確定了某個物件是虛可及物件時, PhantomReference 物件就被放在它的 ReferenceQueue 上。將 PhantomReference 物件放在 ReferenceQueue 上也就是一個通知,表明 PhantomReference 物件引用的物件已經結束,可供收集了。這使您能夠剛好在物件佔用的記憶體被回收之前採取行動。
給個軟引用的例子:
//首先定義一個HashMap,儲存軟引用物件。
private Map<String, SoftReference> imageCache = new HashMap<String, SoftReference>();
//再來定義一個方法,儲存Bitmap的軟引用到HashMap。
public void addBitmapToCache(String path) {
// 強引用的Bitmap物件
Bitmap bitmap = BitmapFactory.decodeFile(path);
// 軟引用的Bitmap物件
SoftReference softBitmap = new SoftReference(bitmap);
// 新增該物件到Map中使其快取
imageCache.put(path, softBitmap);
}
//獲取的時候,可以通過SoftReference的get()方法得到Bitmap物件。
public Bitmap getBitmapByPath(String path) {
// 從快取中取軟引用的Bitmap物件
SoftReference softBitmap = imageCache.get(path);
// 判斷是否存在軟引用
if (softBitmap == null) {
return null;
}
// 取出Bitmap物件,如果由於記憶體不足Bitmap被回收,將取得空
Bitmap bitmap = softBitmap.get();
return bitmap;
}
參考及學習連結:
http://www.cnblogs.com/shudonghe/p/3457990.html
Java 垃圾回收機制技術詳解
http://blog.csdn.net/lu1005287365/article/details/52475957
Java 垃圾回收機制 (GC) 詳解、意義、建議
http://blog.csdn.net/ithomer/article/details/6252552
Java 記憶體模型及GC原理
http://www.codeceo.com/article/java-gc-1.html
Java GC專家系列1:理解Java垃圾回收
http://www.codeceo.com/article/java-gc-2.html
Java GC專家系列2:Java 垃圾回收的監控
http://www.codeceo.com/article/java-gc-learn.html
Java GC 專家系列3:GC調優實踐
Android效能優化-記憶體洩漏的8個Case
http://blog.csdn.net/huoyin/article/details/5891998
Java中三個引用類SoftReference 、 WeakReference 和 PhantomReference的區別
轉載連結:https://www.jianshu.com/p/214e42fc0d37