Java中提供了一个Reference抽象类,此类定义所有引用对象共有的操作,与垃圾收集器密切配合实现的。主要是为了决定某些对象的生命周期,有利于JVM进行垃圾回收。而继承此类的有四种引用,分别是StrongReference(强引用),SoftReference(软引用),WeakReference(弱引用),PhantomReference(虚引用),强度按照上面的顺序依次减弱。下面来看下四种引用的对比。

类型 调用方式 回收条件 内存泄漏
StrongReference 直接调用 不回收 可能
StrongReference get()方法 视内存情况回收 不可能
WeakReference get()方法 永远回收 不可能
PhantomReference 无法取得 不回收 可能
  • 强引用
Object object = new Object()

上面这段代码就是一个强引用,是最普通的引用,当内存空间不足, Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止, 也不会靠随意回收具有强引用的对象来解决内存不足的问。如果想中断或者回收强引用,可以设置引用为null,如object =null,这样的话JVM就会在合适的时间,进行垃圾回收。可以看下下面代码和运行情况。

private static void strongTest() {
printlnMemory("Init");
// 申请5MB的内存
byte[] strong = new byte[5 * MB];
printlnMemory("Use 5MB");
// 回收
System.gc();
printlnMemory("GC after");
System.out.println("gc strong:" + strong);
// 设置引用为null
strong = null;
printlnMemory("set null");
System.out.println("set null strong:" + strong);
// 回收
System.gc();
printlnMemory("null GC after");
System.out.println("gc strong:" + strong);
}

运行情况:

Init:240M(free)/245M(total)

Use 5MB:235M(free)/245M(total)// 使用了5MB内存

GC after:237M(free)/245M(total)// 释放一些内存
gc strong:[B@7ea987ac set null:237M(free)/245M(total)// 强引用设置为null后,内存不变
set null strong:null null GC after:242M(free)/245M(total)//强引用设置为null后,回收5MB内存
gc strong:null
  • 软引用
SoftReference<Object> soft = new SoftReference(new Object());

若一个对象只有软引用,则当空间不足的时候才会回收它,可以用来构建敏感数据的缓存(如网页缓存、图片缓存等)。软引用可以和一个引用队列一同使用,当所引用的对象被回收,软引用便被加入到引用队列。可以看下下面代码和运行情况。

private static void softTest() {
printlnMemory("Init");
SoftReference<byte[]> soft = new SoftReference<>(new byte[2000 * MB]);// 申请2000MB的内存
printlnMemory("Use 2000MB"); System.gc();// gc回收
printlnMemory("GC after");
System.out.println("gc soft:" + soft.get()); SoftReference<byte[]> soft2 = new SoftReference<>(new byte[2000 * MB]);// 再次申请2000MB的内存
printlnMemory("use after");
System.out.println("gc soft:" + soft.get());
}

运行情况

Init:239M(free)/245M(total)

Use 2000MB:239M(free)/2246M(total)//总内存变大了

GC after:243M(free)/2246M(total) //内存足够没有回收
gc soft:[B@2db0f6b2 use after:471M(free)/2474M(total)//内存不够,自动回收
gc soft:null
  • 弱引用
WeakReference<Object> soft = new WeakReference<>(new Object());

弱引用用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。也可以用来构建敏感数据的缓存,如用于生命周期更短的,对内存更敏感的场景中,比如占用内存很大的Map,java提供了WeakHashMap。可以看下下面代码和运行情况

private static void weakTest() {
printlnMemory("Init");
WeakReference<byte[]> weak= new WeakReference<>(new byte[10 * MB]);
printlnMemory("Use 10MB"); System.gc();
printlnMemory("GC after");
System.out.println("gc weak:" + weak.get());
}

运行情况

Init:239M(free)/245M(total)

Use 10MB:229M(free)/245M(total)

GC after:243M(free)/245M(total)//不管内存是否充足,都进行回收
gc soft:null //weak.get无法再回去对象
  • 虚引用
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
PhantomReference<Object> phantom = new PhantomReference<Object>(new Object(), queue);

若一个对象拥有虚引用,则在任何时候都可能被回收。虚引用必须和引用队列联合使用,当所引用的对象被回收,虚引用便被加入到引用队列,主要用来追踪垃圾回收过程。

private static void phantomTest() {
printlnMemory("Init");
byte[] bytes = new byte[5 * MB];
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
PhantomReference<Object> phantom = new PhantomReference<Object>(bytes, queue);
printlnMemory("Use 5MB");
System.out.println("phantom : " + phantom);
System.out.println("phantom.get() : " + phantom.get());
System.out.println("queue.poll() : " + queue.poll());
//断开强引用
bytes = null;
System.gc();
printlnMemory("GC after bytes");
System.out.println("phantom : " + phantom);
System.out.println("phantom.get() : " + phantom.get());
System.out.println("queue.poll() : " + queue.poll()); //断开虚引用
phantom = null;
System.gc();
printlnMemory("GC after phantom");
System.out.println("phantom : " + phantom);
System.out.println("queue.poll() : " + queue.poll());
}

运行情况

Init:239M(free)/245M(total)

Use 5MB:234M(free)/245M(total)
phantom : java.lang.ref.PhantomReference@2db0f6b2
phantom.get() : null
queue.poll() : null GC after bytes:238M(free)/245M(total)
phantom : java.lang.ref.PhantomReference@2db0f6b2
phantom.get() : null
queue.poll() : java.lang.ref.PhantomReference@2db0f6b2 GC after phantom:243M(free)/245M(total)
phantom : null
queue.poll() : null
  • ReferenceQueue

顾名思义存放引用的队列,保存的是Reference对象,其作用在于Reference对象所引用的对象被GC回收时,该Reference对象将会被加入引用队列中的队列末尾。

常用的方法:

  • poll():从队列中取出一个元素,队列为空则返回null
  • remove():从队列中出对一个元素,若没有则阻塞至有可出队元素
  • remove(long timeout):从队列中出对一个元素,若没有则阻塞至有可出对元素或阻塞至超过timeout毫秒;

可以看下下面代码

byte[] bytes = new byte[5 * MB];
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
PhantomReference<Object> phantom = new PhantomReference<Object>(bytes, queue);

这段代码中,对于byte对象有两种引用类型,一是bytes 的强引用,二是phantom 的虚引用。当bytes 被回收时,phantom 所引用的对象将会被放到queue 的队列末尾。利用ReferenceQueue可以清除失去了虚引用对象的引用。

Java四种引用的更多相关文章

  1. Java四种引用包括强引用,软引用,弱引用,虚引用。

    Java四种引用包括强引用,软引用,弱引用,虚引用. 强引用: 只要引用存在,垃圾回收器永远不会回收Object obj = new Object();//可直接通过obj取得对应的对象 如obj.e ...

  2. Java四种引用--《深入理解Java虚拟机》学习笔记及个人理解(四)

    Java四种引用--<深入理解Java虚拟机>学习笔记及个人理解(四) 书上P65. StrongReference(强引用) 类似Object obj = new Object() 这类 ...

  3. 不可访问内存 Java四种引用包括强引用,软引用,弱引用,虚引用

    小结: 1.不可访问内存是指一组没有任何可访问指针指向的由计算机程序进行动态分配的内存块. 2.垃圾收集器能决定是否一个对象还是可访问的:任何被确定不可访问的对象将会被释放. https://zh.w ...

  4. java四种引用及在LeakCanery中应用

    java 四种引用 Java4种引用的级别由高到低依次为: StrongReference > SoftReference > WeakReference > PhantomRefe ...

  5. JAVA四种引用方式

    JAVA四种引用方式: java.lang.ref: 强引用(直接变量赋值) 软引用(SoftReference): 只有在要发生OOM错误之前才会回收掉老的软引用对象,应用场景主要防止内存溢出.(缓 ...

  6. java四种引用与回调函数

    JAVA四种引用 java对象的引用包括: 强引用 软引用 弱引用 虚引用 Java中提供这四种引用类型主要有两个目的: 第一是可以让程序员通过代码的方式决定某些对象的生命周期: 第二是有利于JVM进 ...

  7. 【转】JAVA四种引用(强引用,弱引用,软引用,虚引用)

    转自:http://www.cnblogs.com/gudi/p/6403953.html 1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器 ...

  8. Java 四种引用介绍及使用场景

    强引用-FinalReference 介绍: 强引用是平常中使用最多的引用,强引用在程序内存不足(OOM)的时候也不会被回收,使用方式: String str = new String("s ...

  9. Java基础:Java的四种引用

    在Java基础:java虚拟机(JVM)中,我们提到了Java的四种引用.包括:强引用,软引用,弱引用,虚引用.这篇博客将详细的讲解一下这四种引用. 1. 强引用 2. 软引用 3. 弱引用 4. 虚 ...

随机推荐

  1. 在linux环境下用中文查询数据库

    1.用SQL在linux环境下,查询语句的中文条件,查不到结果. mysql -h ***.***.***.*** -P 3303 -uroot -p*********** -D boztax -e ...

  2. Kali学习笔记20:缓冲区溢出实验环境准备

    在前几篇的博客中:我介绍了OpenVAS和Nessus这两个强大的自动化漏洞扫描器 但是,在计算机领域中有种叫做0day漏洞:没有公开只掌握在某些人手中 那么,这些0day漏洞是如何被发现的呢? 接下 ...

  3. OutOfMemoryError 到底能不能被捕获?

    感觉中,OutOfMemeryError(内存溢出错误) 是jvm抛出的异常,是不能被捕获的. 直到工作中真的遇到OOM异常,而且tomcat服务还一直对外提供服务. 那么问题来了: 1. OOM 到 ...

  4. linux 下zip的用法实例

    zip命令可以用来将文件压缩成为常用的zip格式.unzip命令则用来解压缩zip文件. 1. 我想把一个文件abc.txt和一个目录dir1压缩成为yasuo.zip: # zip -r yasuo ...

  5. npm ERR! Refusing to install package with name "webpack" under a package -----

    当我们在安装以一些依赖的时候会提示以下报错--------- 问题出在: 这个name 不能使用所需要安装包的名字! 解决方案----- 修改下就行 -- -我将wenpack 改成webpack1 ...

  6. python自动化工具之pywinauto(一个实例)结合pyuserinput

    以下是pywinauto使用指南.这个窗口句柄可以在Spy++中查看 (Microsoft Spy++(查看窗口句柄) 10.00.30319 官方最新绿色版) python自动化工具之pywinau ...

  7. select实现高并发服务器

    前言:周末学了两天网络编程,把之前的不懂一些问题基本掌握了,例如TCP状态转换图.close和shutdown函数的区别.select函数等,今天分享给大家. 一.网络编程基础知识 在写代码之前,需要 ...

  8. 多线程编程学习笔记——使用异步IO

    接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...

  9. 手写spring(简易版)

    本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作,如有错误之处忘不吝批评指正! 理解Spring本质: 相信之前在使用spring的时候大家都配置web.x ...

  10. HTTPS过程以及详细案例

    1.HTTPS的过程 1.客户端向服务端发送请求,客户端主要向服务器提供以下信息: 支持的协议版本,比如TLS 1.0版. 一个客户端生成的随机数,稍后用于生成"对话密钥". 支持 ...