深入JVM对象引用

作者: Android高级架构探索 | 来源:发表于2018-10-22 14:12 被阅读2次

在jdk 1.2以前,创建的对象只有处在可触及(reachaable)状态下,才能被程序所以使用,垃圾回收器一旦发现无用对象,便会对其进行回收。但是,在某些情况下,我们希望有些对象不需要立刻回收或者说从全局的角度来说并没有立刻回收的必要性。比如缓存系统的设计,在内存不吃紧或者说为了提高运行效率的情况下,一些暂时不用的对象仍然可放置在内存中,而不是立刻进行回收。因此,从jdk 1.2 版本开始,java设计人员把对象的引用细分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)四种级别,主要区别体现在在被GC回收的优先级上:强引用->软引用->弱引用->虚引用。也就是说从jdk 1.2开始,垃圾回收器回收对象时,对象的可达性分析需要考虑考虑对象的引用强度,也就是说现在对象的有效性=可达性+引用类型。先来看下类层次结构如下:


image.png

1. 引用的四种类型

1. 强引用(Strong Reference)

在代码中普遍使用的,类似Person person=new Person();如果一个对象具有强引用,则无论在什么情况下,GC都不会回收被引用的对象。当内存空间不足时,JAVA虚拟机宁可抛出OutOfMemoryError终止应用程序也不会回收具有强引用的对象。

2. 软引用(Soft Reference)

表示一个对象处在有用但非必须的状态。如果一个对象具有软引用,在内存空间充足时,GC就不会回收该对象;当内存空间不足时,GC会回收该对象的内存(回收发生在OutOfMemoryError之前)。

1.Person person=new Person();
2.SoftReference sr=new SoftReference(person);

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被GC回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中,以便在恰当的时候将该软引用回收。但是由于GC线程的优先级较低,通常手动调用System.gc()并不能立即执行GC,因此弱引用所引用的对象并不一定会被马上回收。

3. 弱引用(Weak Reference)

用来描述非必须的对象。它类似软引用,但是强度比软引用更弱一些:弱引用具有更短的生命.GC在扫描的过程中,一旦发现只具有被弱引用关联的对象,都会回收掉被弱引用关联的对象。换言之,无论当前内存是否紧缺,GC都将回收被弱引用关联的对象。

1.Person person=new Person();
2.WeakReference wr=new WeakReference(person);

同样弱引用也可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被GC回收了,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中,以便在恰当的时候将该弱引用回收。

4. 虚引用(Phantom Reference)

虚引等同于没有引用,这意味着在任何时候都可能被GC回收,设置虚引用的目的是为了被虚引用关联的对象在被垃圾回收器回收时,能够收到一个系统通知。(被用来跟踪对象被GC回收的活动)虚引用和弱引用的区别在于:虚引用在使用时必须和引用队列(ReferenceQueue)联合使用,其在GC回收期间的活动如下:

1.ReferenceQueue queue=new ReferenceQueue();
2.PhantomReference pr=new PhantomReference(object.queue);

也即是GC在回收一个对象时,如果发现该对象具有虚引用,那么在回收之前会首先该对象的虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入虚引用来了解被引用的对象是否被GC回收。
ReferenceQueue和Reference

  1. ReferenceQueue含义及作用
    通常我们将其ReferenceQueue翻译为引用队列,换言之就是存放引用的队列,保存的是Reference对象。其作用在于Reference对象所引用的对象被GC回收时,该Reference对象将会被加入引用队列中(ReferenceQueue)的队列末尾,这相当于是一种通知机制.当关联的引用队列中有数据的时候,意味着引用指向的堆内存中的对象被回收。通过这种方式,JVM允许我们在对象被销毁后,做一些我们自己想做的事情。JVM提供了一个ReferenceHandler线程,将引用加入到注册的引用队列中

ReferenceQueue常用的方法:
public Reference<? extends T> poll():从队列中取出一个元素,队列为空则返回null;

public Reference<? extends T> remove():从队列中出对一个元素,若没有则阻塞至有可出队元素;

public Reference<? extends T> remove(long timeout):从队列中出对一个元素,若没有则阻塞至有可出对元
素或阻塞至超过timeout毫秒;

见如下代码:


image.png

这段代码中,对于Person对象有两种引用类型,一是person的强引用,而是sr的软引用。sr强引用了SoftReference对象,该对象软引用了Person对象。当person被回收时,sr所强引用的对象将会被放到rq的队列末尾。利用ReferenceQueue可以清除失去了软引用对象的SoftReference,如下操作:


image.png
  1. Reference类
    Reference是SoftReference,WeakReference,PhantomReference类的父类,其内部通过一个next字段来构建了一个Reference类型的单向列表,而queue字段存放了引用对象对应的引用队列,若在Reference的子类构造函数中没有指定,则默认关联一个ReferenceQueue.NULL队列。

  2. 四种引用类型使用场景
    强引用类型是在代码中普遍存在,无须解释太多了
    软引用和弱引用:两者都可以实现缓存功能,但软引用实现的缓存通常用在服务端,而在移动设备中的内存更为紧缺,对垃圾回收更为敏感,因此android中的缓存通常是用弱引用来实现(比如LruCache)
    在开发中有这么一个场景:用户信息查询。在不考虑对用户信息更改的情况下,通常有以下两种方案来实现:

  3. 每次查询时,连接数据库获取信息,缺点是IO读频繁,平均响应时间较长。优点是内存占用少。

  4. 第一次查询时,读取数据库后将用户信息存放在内存中,以后每次查询从内存中读取,优点是读取速度快,在请求次数较少的情况下,内存占用较多。
    现在我们用采用第二种方案,基于缓存来设计,代码如下:


    image.png
    image.png
    image.png
    image.png
    image.png

    这样简单的缓存就完成了,输出结果如下:


    image.png

4. 到底是什么引用类型?

如果一个对象有多个引用类型,那在进行垃圾回收时如何判断对象的可达性呢?其原则如下:

单挑引用链的可达性以最弱的一个引用类型来决定;
多条引用链的可达性以最强的一个引用类型来决定;

举例说明,如下图所示:


image.png

对Object 2进行分析,路径1-1——>2-1中取最弱的引用,软引用;路径1-2——>2-2中取最弱引用,虚引用;在这两条路径中取最强引用,软引用。因此Object 2是最终的引用类型是软引用。


示例代码

我们通过一段代码帮助理解这四种:


image.png

相关文章

  • 深入JVM对象引用

    在jdk 1.2以前,创建的对象只有处在可触及(reachaable)状态下,才能被程序所以使用,垃圾回收器一旦发...

  • JVM对象引用与内存分配策略

    我的CSDN博客同步发布:JVM对象引用与内存分配策略 前两天对《深入理解虚拟机》一书做了个总结:《JVM理解其实...

  • 强引用,软引用,弱引用,虚引用 浅析

    强引用StrongReference 最常见的引用类型,jvm即使是oom也不会回收拥有强引用的对象, 上面的对象...

  • android的四种引用

    强引用:普通new对象的引用 User user = new User(); jvm宁愿抛出OutOfMemory...

  • 深入理解java虚拟机(二)-对象存活判定、引用与方法区回收

    本文基于周志明的《深入理解java虚拟机 JVM高级特性与最佳实践》所写。特此推荐。 对象存活判定算法 引用计数算...

  • JVM读书笔记

    深入理解JVM(1) : Java内存区域划分 深入理解JVM(2) : Java堆中对象创建、布局、访问全过程 ...

  • 强引用、软引用、弱引用、虚引用总结

    强引用:普通new对象的引用 StrongReference jvm宁愿抛出OutOfMemory异常也不会去回收...

  • 四种引用

    强引用(new)只要强引用存在,GC就永远不会回收被引用的对象。只要某个对象与强引用关联,那么JVM在内存不足的情...

  • 垃圾回收机制

    垃圾对象内存中不再被使用的对象。垃圾回收(GC)jvm自动释放垃圾对象所占内存的机制。如果对象再没有被引用变量引用...

  • JVM - GC算法

    JVM - GC算法 对象存活判断算法 引用计数法:每个对象内置一个引用计数器,新增引用时,计数器加1,释放引用时...

网友评论

    本文标题:深入JVM对象引用

    本文链接:https://www.haomeiwen.com/subject/kwqgzftx.html