JVM【day6】

垃圾回收

如何判断对象可以回收

引用计数法

只要一个对象被其他变量所引用,就让其计数加一,引用两次就加二,如果某一个变量不再引用,就让其计数减一,如果其计数为0,就可以进行回收
弊端:循环引用
在这里插入图片描述

可达性分析算法(jvm使用的一种算法)

首先确定一系列根对象(肯定不能当成垃圾回收的对象),在垃圾回收前,首先对堆中所有对象进行扫描,看此对象是否被根对象直接或间接引用,如果被引用,则此对象不能被垃圾回收,反之会被垃圾回收
哪些对象可以作为根对象?
使用Eclipse中的Memory Analyzer(MAT),是一个java堆的分析工具,可以帮助你找到内存的泄露,减少内存的耗费

四种引用

如图:
在这里插入图片描述
实线箭头表示强引用,虚线的表示其他引用
强引用
平时用的所有引用都属于强引用,如:List<Object> list1 = new ArrayList<>();,只有所有GC Roots对象都不通过【强引用】引用该对象,该对象才能被垃圾回收
软引用

  • 仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次出发垃圾回收,回收软引用对象
  • 可以配合引用队列来释放软引用自身

弱引用

  • 仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象
  • 可以配合引用队列来释放弱引用自身

软引用和弱引用比较像,只要对象没有被直接的强引用所引用,那么当垃圾回收时,都有可能被回收,当没有强引用对象引用时:A2对象,如果没有B对象直接引用,当内存不足时,会被垃圾回收,A3对象,如果没有B对象直接引用,发生垃圾回收时,不管内存够不够,都会回收A3对象,这两种既可以配合引用队列使用,也可以不配合引用队列使用
虚引用

  • 必须配合引用队列使用,主要配合 ByteBuffer使用,被引用对象回收时,会将虚引用入队,由Reference
    Handler线程调用虚引用相关方法释放直接内存

终结器引用

  • 无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由Finalizer线程通过终结器引用找到被引用对象并调用它的finalize方法,第二次GC时才能回收被引用对象

用以下代码演示软引用:
-Xmx20m -XX:+PrintGCDetails -verbose:gc,设置参数

public class Demo_12 {
    private static final int _4MB=4*1024*1024;
    public static void main(String[] args) throws IOException {
        //强引用,会发生报错
        //不太重要的资源,在内存紧张时应该释放掉,以后再读取资源即可
       /* List<byte[]>list=new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            list.add(new byte[_4MB]);
        }
        System.in.read();*/
        soft();
    }
    public static void soft(){
        //list-->SoftReference(软引用对象)-->byte[]
        List<SoftReference<byte[]>>list=new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            SoftReference<byte[]>ref=new SoftReference<>(new byte[_4MB]);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }
        System.out.println("循环结束:"+list.size());
        for(SoftReference<byte[]>ref:list){
            System.out.println(ref.get());
        }
    }
}

运行强引用结果如下:
在这里插入图片描述
使用软引用结果如下:
在这里插入图片描述
应用了软引用的特性,当空间不足时,垃圾回收会把软引用对象回收掉
清理无用的软引用:需要引用队列对象对软引用进行清理
代码如下:

public class Demo_13 {
    private static final int _4MB=4*1024*1024;
    public static void main(String[] args) {
        //list-->SoftReference(软引用对象)-->byte[]
        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("循环结束:"+list.size());
        for(SoftReference<byte[]>ref:list){
            System.out.println(ref.get());
        }
    }
}

结果如下:
在这里插入图片描述
可以看到四个null也被回收了

用以下代码演示弱引用:

/*-Xmx20m  -XX:+PrintGCDetails -verbose:gc*/
public class Demo_14 {
    private static final int _4MB=4*1024*1024;
    public static void main(String[] args) {
        List<WeakReference<byte[]>> list=new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            WeakReference<byte[]>ref=new WeakReference<>(new byte[_4MB]);
            list.add(ref);
            for(WeakReference<byte[]>w:list){
                System.out.println(w.get()+" ");
            }
            System.out.println();
        }
        System.out.println("循环结束:"+list.size());

    }
}

运行结果如图:
在这里插入图片描述
将循环次数改成10,结果如下:
在这里插入图片描述
可以发现,触发了一次full gc,使得前面的都变成了null,因为弱引用本身也占一点内存,清除弱引用和清除软引用方法相同

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值