JVM內存-GC策略

在思考GC時一般須要完成3件事情:

  • 哪些內存須要回收?
  • 何時回收?
  • 如何回收?

引用計數器算法GC存在的問題是?html


描述:引用計數器法給對象中添加一個引用計數器,沒當一個地方引用它,計數器就加一,引用失效時減一,任何引用計數器爲0的對象就是不可能再被使用的對象。java

引用計數器算法的效率也比較高,主流的JVM裏面並無選用引用計數器來管理內存,其中最主要的問題是不能解決對象之間循環引用的問題。算法

jvm可達性分析算法

java是經過可達性分析來判斷對象是否存活,這個算法的基本思路是經過一系列的稱爲「GC Roots」的對象爲起始點,從這些節點向下搜索,搜索全部的路徑稱爲引用鏈;引用鏈不能到達的對象節點是GC須要回收的。緩存

在java語言中可被稱爲「GC Roots」的對象包括下面幾個方面:bash

  • 1.虛擬機棧中引用的對象
  • 2.方法區中類靜態屬性引用的對象
  • 3.方法區中常量引用的對象
  • 4.本地方法(Native)引用的對象

不管是引用計數器仍是可達性分析判斷的標準都是對象是否引用。jvm

在jdk1.2後,java對引用進行了擴充,將引用分爲強引用 、軟引用、弱引用、虛引用4種,強弱依次遞減。性能

  • 強引用:相似「Object obj = new Object()」,只要存在,GC永不回收
public class Main {
    public static void main(String[] args) {
        new Main().fun1();
    }
     
    public void fun1() {
        Object object = new Object();
        Object[] objArr = new Object[1000];
    }
}
複製代碼
  • 軟引用:軟引用是用來描述一些有用但並非必需的對象,在Java中用java.lang.ref.SoftReference類來表示。對於軟引用關聯着的對象,只有在內存不足的時候JVM纔會回收該對象。如:
import java.lang.ref.SoftReference;
 
public class Main {
    public static void main(String[] args) {
         
        SoftReference<String> sr = new SoftReference<String>(new String("hello"));
        System.out.println(sr.get());
    }
}
複製代碼

  • 弱引用也是用來描述非必需對象的,當JVM進行垃圾回收時,不管內存是否充足,都會回收被弱引用關聯的對象。在java中,用java.lang.ref.WeakReference類來表示。下面是使用示例:
public class Main {
    public static void main(String[] args) {
     
        WeakReference<String> sr = new WeakReference<String>(new String("hello"));
         
        System.out.println(sr.get());
        System.gc();                //通知JVM的gc進行垃圾回收
        System.out.println(sr.get());
    }
}
複製代碼

  • 虛引用和前面的軟引用、弱引用不一樣,它並不影響對象的生命週期。在java中用java.lang.ref.PhantomReference類表示。若是一個對象與虛引用關聯,則跟沒有引用與之關聯同樣,在任什麼時候候均可能被垃圾回收器回收。
ReferenceQueue<String> queue = new ReferenceQueue<String>();
        PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);
        System.out.println(pr.get());
複製代碼

如何利用軟引用和弱引用解決OOM問題優化

  前面講了關於軟引用和弱引用相關的基礎知識,那麼到底如何利用它們來優化程序性能,從而避免OOM的問題呢?spa

  下面舉個例子,假若有一個應用須要讀取大量的本地圖片,若是每次讀取圖片都從硬盤讀取,則會嚴重影響性能,可是若是所有加載到內存當中,又有可能形成內存溢出,此時使用軟引用能夠解決這個問題。線程

  設計思路是:用一個HashMap來保存圖片的路徑 和 相應圖片對象關聯的軟引用之間的映射關係,在內存不足時,JVM會自動回收這些緩存圖片對象所佔用的空間,從而有效地避免了OOM的問題。在Android開發中對於大量圖片下載會常常用到。      

生存仍是死亡

要宣告一個對象死亡,至少經歷兩次標記過程:若是進行可達性分析時沒有到達的引用鏈,將會作第一次標記,此處須要進行一次篩選,條件是有必要執行finalize()方法,當對象沒有覆蓋finalize(),或者已經被jvm調用,這兩種狀況稱爲「沒有必要執行」;若是對象被判斷有必要執行,會被放置在一個F-Queue隊列,稍後有優先級低的線程進行第二次標記,若是對象finalize從新進行了引用,那麼將會移出回收隊列,不然會被進行垃圾回收。

回收方法區

判斷一個類須要回收的條件:

  • 該類的全部實例已經被回收,也就是堆中不存在該類的實例
  • 加載該類的ClassLoader已經被回收
  • 該類的Class對象沒有在任何地方引用,沒有使用到反射的方法            

參考書籍: 深刻理解jvm

引用博客: https://www.cnblogs.com/dolphin0520/p/3784171.html

相關文章
相關標籤/搜索