JVM學習筆記——垃圾回收篇( 二 )

我們再給出軟引用對象回收的相關測試代碼:
package cn.itcast.jvm.t2;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.lang.ref.SoftReference;import java.util.ArrayList;import java.util.List;/** * 演示軟引用, 配合引用隊列 */public class Demo2_4 {private static final int _4MB = 4 * 1024 * 1024;public static void main(String[] args) {// 這里設置了List , 里面的SoftReference是軟引用對象 , 再在里面添加的數據就是軟引用對象所引用的A2對象List<SoftReference<byte[]>> list = new ArrayList<>();// 引用隊列(類型和引用對象的類型相同即可)ReferenceQueue<byte[]> queue = new ReferenceQueue<>();for (int i = 0; i < 5; i++) {// 關聯了引用隊列,當軟引用所關聯的 byte[]被回收時,軟引用自己會加入到 queue 中去SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB], queue);System.out.println(ref.get());list.add(ref);System.out.println(list.size());}// 從隊列中獲取無用的 軟引用對象,并移除Reference<? extends byte[]> poll = queue.poll();while( poll != null) {list.remove(poll);poll = queue.poll();}System.out.println("===========================");for (SoftReference<byte[]> reference : list) {System.out.println(reference.get());}}}/*和之前那此調試相同,前四次正常運行,在第五次時進行了gc清理但是在循環結束之后,我們將軟引用對象放入到了引用隊列中并進行了清理,所以這時我們的list中前四次軟引用對象直接消失我們只能看到list中只有一個對象:[B@330bedb4*/弱引用上述圖片中的A3對象就是弱引用示例
我們下面介紹強弱引用的概念:

  • 弱引用不是由根Root直接引用,而是采用一個弱引用對象WeakReference連接
然后我們介紹弱引用的回收概念:
  • 當該對象沒有被強引用連接,被弱引用連接時在進行Full gc時會被強制回收
  • 每次進行老年代的Full gc(后面會講到Full gc,這里就當作大型垃圾回收)時都會被強制回收
此外我們的弱引用對象也是會占用內存的 , 所以我們也需要采用相同方法將弱引用對象回收:
  • 我們通常將弱引用對象綁定一個引用隊列
  • 當該弱引用對象不再連接任何對象時 , 將其放入引用隊列 , 引用隊列會進行檢測 , 檢測到弱引用對象就會對其進行垃圾回收
我們同樣給出弱引用對象的垃圾回收示例代碼:
package cn.itcast.jvm.t2;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.lang.ref.SoftReference;import java.lang.ref.WeakReference;import java.util.ArrayList;import java.util.List;/** * 演示弱引用 * -Xmx20m -XX:+PrintGCDetails -verbose:gc */public class Demo2_5 {private static final int _4MB = 4 * 1024 * 1024;public static void main(String[] args) {//list --> WeakReference --> byte[]List<WeakReference<byte[]>> list = new ArrayList<>();for (int i = 0; i < 10; i++) {WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB]);list.add(ref);for (WeakReference<byte[]> w : list) {System.out.print(w.get()+" ");}System.out.println();}System.out.println("循環結束:" + list.size());}}/*這時我們的小型gc(新生代gc)是不會觸發弱引用全部刪除的(新生代我們后面會講到)只有當內存全部占滿后,觸發的Full gc才會導致弱引用的必定回收例如我們在第5,7次新生代發生內存占滿,這時觸發了新生代的gc,但是只會刪除部分WeakReference當我們第9次新生代,老生代內存全部占滿后會發生一次Full gc,這時就會引起全部弱引用數據刪除,所以我們的數據會變成:nullnullnullnullnullnullnullnullnull[B@330bedb4*/虛引用上述圖片中的ByteBuffer對象就是虛引用示例
我們下面介紹虛引用的概念:
  • 虛引用實際上就是直接內存的引用,我們內存結構篇所學習的ByteBuffer就是例子
  • 系統首先會創建一個虛引用,然后這個虛引用會創建一個ByteBuffer對象,ByteBuffer對象通過unsafe來管理直接內存
  • 此外,我們的虛引用必定需要綁定一個引用隊列,因為我們的byteBuffer對象是無法控制直接內存的,我們需要檢測虛引用來刪除
然后我們介紹虛引用的回收概念:
  • 首先我們會手動刪除或者系統垃圾回收掉ByteBuffer對象
  • 這時我們的虛引用和直接內存是不會消失的,但是我們的虛引用會被帶到引用隊列中
  • 虛引用中攜帶者Cleaner對象,引用隊列會一直檢測是否有Cleaner對象進入,當檢測到時會執行這個Cleaner方法來刪除直接內存
我們需要注意的是: