【深入理解JVM-Java的四种引用&finalize】

为啥要引进四种引用?

jdk1.2之前的引用定义:如果reference类型的数据中存储的数值代表另一块内存的起始地址,就称这块内存代表着一个引用。
上述弊端:一个对象只能表示两种状态,即被引用,未被引用。
如果我们希望描述这样一类对象:当内存空间足够时则保留在内存中,如果内存空间在进行垃圾收集后还是比较紧张则可以抛弃这些对象。于是jdk1.2之后扩展了引用。

引用分类

1、强引用(StrongReference)

强引用就是指在程序代码中普遍存在的,类似Object o = new Object()这类的引用。如果一个对象持有强引用,那么垃圾回收器绝不会回收他,当内存空间不足时,jvm宁愿抛出OutOfMemoryError使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
ps:如果强引用不在使用时可以赋值为null,这样垃圾回收器则认为对象未被引用,在合适的时候便会进行回收。

2、软引用(SoftReference)
  • 作用:用来描述一些有用但并非重要的对象。
  • 特点:
    1、系统内存空间充足时,垃圾回收器不会回收它。只要垃圾回收器没有回收它,该对象就可以被程序使用。
    2、系统内存空间不足时(将要发生oom之前),回收这些对象的内存。如果回收后还是没有足够的内存这时才会抛出oom error。
    3、软引用可以和引用队列ReferenceQueue联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中
  • 使用场景:用于内存敏感的高速缓存。在 jvm 报告内存不足之前会清除所有的软引用,这样以来 gc 就有可能收集软可及的对象,可能解决内存吃紧问题,避免内存溢出。
       
        ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
         //SoftReference 简单使用
        String str = new String("aaa");
        SoftReference<String> softReference = new SoftReference<>(str,referenceQueue);
        String s = softReference.get();//垃圾回收了这里就返回null,不回收就返回相应对象
        System.out.println(s);

        Reference<? extends String> reference = referenceQueue.poll(); 

补充:

  • 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java 虚拟机就会把这个软引用加入到与之关联的引用队列中。

  • 什么时候会被收集取决于 gc 的算法和 gc 运行时可用内存的大小

  • 对 ReferenceQueue 软引用和弱引用可以有可无,但是虚引用必须有。

3、弱引用(WeakReference)
  • 作用:用来描述非必要的对象
  • 特点:
    1、如果一个对象只具有弱引用,那该类就是可有可无的对象,因为只要该对象被 gc 扫描到了随时都会把它干掉。
    2、只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存,不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。
    3、 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中
  • 使用场景:
    1、防止内存泄漏:内部类非静态对象持有外部类引用
    2、监控对象是否将要被回收
        //WeakReference 基本使用
        ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();

        String str = new String("aaa");
        WeakReference<String> weakReference = new WeakReference<>(str,referenceQueue);
        String s = weakReference.get();
        System.out.println("s:"+s);
        System.gc();//通知系统进行垃圾回收,但是系统不一定执行
        System.out.println("isEnqueued:"+weakReference.isEnqueued());// 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中
        System.out.println(weakReference.get());
4、虚引用(PhantomRefrence 对)

特点:
1、虚引用并不会决定对象的生命周期,即无法通过虚引用来获得对象的实例。
2、如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
作用:
虚引用主要用来跟踪对象被垃圾回收的活动。当垃圾回收器回收对象时虚引用会收到系统通知。
使用场景:判断对象是否将要被回收。
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要进行垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动,也可以理解为对象回收的一种回调方法。

        String string = new String("aaa");
        ReferenceQueue queue = new ReferenceQueue();
        PhantomReference phantomReference = new PhantomReference(string, queue);
        string = null;
        String s1 = (String) phantomReference.get();//null
        System.out.println("s1:"+s1);
        // 判断是否入队(入队则表示要被jvm回收)
        System.out.println("isEnqueued:"+phantomReference.isEnqueued());

Object的finalize

1、方法介绍

Object的方法,内部空实现。任何Java类都可以重写Object类的finalize()方法,在该方法中清理该对象占用的资源。当finalize()方法返回后,对象消失,垃圾回收机制开始执行。

  protected void finalize() throws Throwable { }
2、finalize 方法特点
  • 不要主动调用某个对象的finalize()方法,该方法是垃圾回收机制在回收某个对象之前进行调用。由jvm调用。
  • finalize()方法何时被调用,是否被调用具有不确定性,不要把finalize()方法当成一定会被执行的方法。
  • 当JVM执行可恢复对象的finalize()方法时,可能使该对象或系统中其他对象重新变成可达状态(finalize方法中进行了某些对象自救)
  • 当JVM执行finalize()方法时出现异常时,垃圾回收机制不会报告异常,程序继续执行。

场景解释:

1、如果程序终止之前始终没有进行垃圾回收,则不会调用失去引用对象的finalize()方法来清理资源。
2、某个失去引用的对象只占用了少量内存,而且系统没有产生严重的内存需求,因此垃圾回收机制并没有试图回收该对象所占用的资源,所以该对象的finalize()方法也不会得到调用

触发demo:


/**
 * Create by SunnyDay on 2020/10/09
 */
public class FinalizeMethod {


    public static void main(String[] args) {
        Person person = new Person();

        ReferenceQueue referenceQueue = new ReferenceQueue();
        PhantomReference<Person> personPhantomReference = new PhantomReference<>(person, referenceQueue);
        person = null;
        System.gc(); // 通知系统,建议gc
     
    }
}

class Person {
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize");
    }
}

// log:
finalize

Process finished with exit code 0

总结:finalize 由jvm调用,调用具备不确定性。不建议开发者使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值