Java 的內存模型、垃圾回收機制和四種引用方式

1、內存模型

Java中的內存分爲五個部分,分別是方法區、虛擬機棧、堆、程序計數器和本地方法區。算法

1.方法區

存放運行時加載的類信息、靜態變量、常量等信息。緩存

2.虛擬機棧

存放對象的引用、方法的返回地址等。 每一個線程都有一個棧。spa

3.堆

主要存放對象的實例。 全部線程共享同一個堆。線程

4.程序計數器

存放運行程序的行數信息。code

5.本地方法區

和方法區相似,但存放的native方法的相關內容。對象

2、垃圾回收

1.垃圾回收的對象

清理的內容主要是存在於堆和方法區的內容。生命週期

2.清理方法

方法一:引用計數:當一個對象被引用次數+1,引用釋放時次數-1,=0時便可回收。可是存在互相引用問題,會致使沒法回收。 方法二:可達性分析:當一個對象沒有經過引用鏈和GC roots相連的時候,就表示已經沒有用,能夠回收了。 GC roots有哪些? - 虛擬機(棧幀中的本地變量表)中引用的對象 - 方法區中類靜態屬性引用的對象 - 方法區中常量引用的對象 - 本地方法棧中JNI(即通常說的native方法)中引用的對象隊列

3.清理分類和觸發條件

  1. MINOR GC eden滿的時候觸發。
  2. FULL GC 調用System.gc()會被建議使用full; 老年區空間不足; 方法區空間不足; MINOR GC方法空間沒法知足

4.垃圾回收算法

  1. 標記-清除法
    • 作法: 當發現須要回收的內容時,標記並直接清除。
    • 缺點: 須要遍歷全堆,複雜度高,而且會帶來內存碎片等問題
  2. 標記-整理法
    • 作法: 將不須要回收的內容標記並整理到一塊兒,而後清除剩下的部分
    • 優缺點: 沒有內存碎片問題;可是若是存活的多,會產生屢次搬運,下降效率。
  3. 複製法
    • 作法: 將內存分兩塊,每次將存活的對象搬運到另外一塊,並清理這一塊。
    • 優缺點 清理容易,可是內存利用率低。
  4. 分代收集法
    • 理論: 新建立的對象通常都是生命週期較短的,分塊能夠優先回收這些。
    • 作法:
      1. 內存分年輕代和年老代,年輕代再分爲3區,eden區和a區、b區。新建的對象放在年輕代的eden區;
      2. 當eden區滿了,對eden進行gc,把存活的搬入a區
      3. 當eden再次滿了,對eden和a區進行gc,將eden區和a區的存活的搬入b區;
      4. 重複二、3步,直到必定次數後,將仍然存活、在a、b區反覆搬運的內容搬入年老區;
      5. 年老區滿了之後,進行全量gc,即對全部的區都作gc,是最慢的。
    • 優缺點 挺好的,如今都用分代收集法。

5.垃圾回收的實現

1. 串行回收
2. 並行回收
3. 與用戶線程同存的回收
4. G1回收

3、引用方式

強引用(FinalReference)

即便OOM也不會被清理。對對象的引用默認就是這種方式。例如,Object o = new Object();
【FinalReference類不是public的,沒辦法直接用】

軟引用(SoftReference)

當內存不足的時候會被清理。比較適用於緩存。

弱引用(WeakReference)

當沒有再被引用時,隨時都有可能被清理。
這裏寫一個小例子來展現弱引用的效果。
    public static void main(String[] args) throws InterruptedException {
        AtomicInteger integer = new AtomicInteger(12);
        WeakReference<AtomicInteger> reference = new WeakReference<>(integer);
        System.out.println("正在使用時,reference.get()="+reference.get());
        System.gc();
        System.out.println("引用的對象還引用着,reference.get()="+reference.get());
        integer = null;
        System.out.println("引用的對象置空了,可是還未進行垃圾回收,reference.get()="+reference.get());
        System.gc();
        System.out.println("引用的對象置空了,垃圾回收後,reference.get()="+reference.get());
    }
運行結果:
    正在使用時,reference.get()=12
    引用的對象還引用着,reference.get()=12
    引用的對象置空了,可是還未進行垃圾回收,reference.get()=12
    引用的對象置空了,垃圾回收後,reference.get()=null
能夠看到:
    被弱引用的對象在尚未結束生命週期時,即便gc也不會被清理;
    當將被弱引用的對象生命週期結束(=null)時,當即去引用裏get(),仍然能夠拿到,證實了這一刻還未被回收;
    再次調用gc(),這時再get()就已經沒有了。

若是把WeakReference換成SoftReference,那麼最後一次get的時候就不會是null。

虛引用(PhantomReference)

相似於弱引用,可是在被即將收集時,會被放入一個引用隊列。用戶能夠查詢引用隊列看是否該對象會被清理,進行一些額外的操做。
相關文章
相關標籤/搜索