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方法来删除直接内存
我们需要注意的是: