Java中四种引用:强、软、弱、虚引用

时间:2022-10-16 23:37:13

这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173

Java中四种引用:强、软、弱、虚引用

1.1、强引用
当我们使用new 这个关键字创建对象时,被创建的对象就是强引用,如Object object = new Object() 这个Object()就是一个强引用。如果一个对象具有强引用,垃圾回收器就不会去回收有强引用的对象,如当jvm内存不足时,具备强引用的对象,虚拟机宁可会报内存空间不足的异常来终止程序,也不会靠垃圾回收器去回收该对象来解决内存。

1.2、软引用

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;

如果内存空间不足了,就会回收这些对象的内存。

只要垃圾回收器没有回收它,该对象就可以被程序使用。

软引用可用来实现内存敏感的高速缓存(下文给出示例)。

软引用可以和一个引用队列(ReferenceQueue)关联使用:

String str = new String("test");
ReferenceQueue<String> rq = new ReferenceQueue<>();
SoftReference sf = new SoftReference(str,rq);

如果软引用(sf)所引用的对象(str)被垃圾回收器回收,Java虚拟机就会把这个软引用(sf)加入到与之关联的引用队列(rq)中,之后可以通过循环调用rq的poll()方法,来清除无用的软引用对象(sf)

如果软引用所引用的对象(str)还没有被垃圾回收器回收,则可以通过这个引用(sf)的get()方法重新获得对引用对象(str)的强引用.

1.3、弱引用
如果一个对象只具有弱引用,只要垃圾回收器在自己的内存空间中线程检测到了,就会立即被回收,对应内存也会被释放掉。相比软引用弱引用的生命周期要比软引用短很多。不过,如果垃圾回收器是一个优先级很低的线程,也不一定会很快就会释放掉软引用的内存。

通俗的来说就是:发生GC时必定回收弱引用指向的内存空间。

示例代码:

public static void main(String[] args) {
String string = new String("test");
ReferenceQueue<String> rq = new ReferenceQueue<>();
WeakReference<String> wr = new WeakReference<String>(string,rq);
System.out.println(wr.get());
string = null;
System.gc();
System.out.println(wr.get());
}

运行结果:

test
null

1.4、虚引用

又称为幽灵引用或幻影引用,虚引用既不会影响对象的生命周期,也无法通过虚引用来获取对象实例,仅用于在发生GC时接收一个系统通知。

相关问题一、若一个对象的引用类型有多个,那到底如何判断它的可达性呢?其实规则如下:

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

Java中四种引用:强、软、弱、虚引用

我们假设图2中引用①和③为强引用,⑤为软引用,⑦为弱引用,对于对象5按照这两个判断原则,路径①-⑤取最弱的引用⑤,因此该路径对对象5的引用为软引用。同样,③-⑦为弱引用。在这两条路径之间取最强的引用,于是对象5是一个软可及对象(当将要发生OOM时则会被回收掉)。

相关问题二、与引用相关联的引用队列的作用是什么

引用队列的作用:使用ReferenceQueue清除失去了引用对象的Reference(SoftReference,WeakReference等)
作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。在java.lang.ref包里还提供了ReferenceQueue。如果在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为参数提供给SoftReference的构造方法,如:
ReferenceQueue queue = new ReferenceQueue();
SoftReference ref=new SoftReference(aMyObject, queue);
那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。
在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收。于是我们可以把这些失去所软引用的对象的SoftReference对象清除掉。常用的方式为:
SoftReference ref = null;
while ((ref = (EmployeeRef) q.poll()) != null) {
// 清除ref
}
理解了ReferenceQueue的工作机制之后,我们就可以开始构造一个Java对象的高速缓存器了。下面是一个高速缓存器的代码:
EmployeeCache 类:
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Hashtable; public class EmployeeCache {
static private EmployeeCache cache;
private Hashtable<String, EmployeeRef> employeeRefs;
private ReferenceQueue<Employee> q;
private class EmployeeRef extends SoftReference<Employee>{
private String _key="";
public EmployeeRef(Employee em,ReferenceQueue<Employee> q) {
super(em,q);
_key=em.getId();
}
}
private EmployeeCache() {
employeeRefs = new Hashtable<>();
q = new ReferenceQueue<>();
} public static EmployeeCache getInstance(){
if(cache==null){
cache = new EmployeeCache();
}
return cache;
} private void cacheEmployee(Employee em){
cleanCache();
EmployeeRef ref = new EmployeeRef(em, q);
employeeRefs.put(em.getId(), ref);
} public Employee getEmployee(String id){
Employee employee = null;
if(employeeRefs.contains(id)){
EmployeeRef ref = employeeRefs.get(id);
employee = ref.get();
} if(employee == null){
employee = new Employee(id);
System.out.println("从信息中心获取新的对象");
this.cacheEmployee(employee);
}
return employee;
}
private void cleanCache() {
EmployeeRef ref = null;
while((ref=(EmployeeRef) q.poll())!=null){
employeeRefs.remove(ref._key);
}
}
public void clearCache(){
cleanCache();
employeeRefs.clear();
System.gc();
System.runFinalization();
}
}

Employee类:

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference; public class Employee {
private String id;
private String name;
private String department;
private String phone;
private int salary;
private String origin; public Employee(String id) {
this.id = id;
getDataFromInfoCenter();
} private void getDataFromInfoCenter() { } public String getId() {
String id = (int) (Math.random() * 10 + 1) + "";
return id;
}
}
 

2、jdk中的引用实现类

代表软引用的类:java.lang.ref.SoftReference
代表弱引用的类:java.lang.ref.WeakReference
代表虚引用的类:java.lang.ref.PhantomReference
他们同时继承了:java.lang.ref.Reference
引用队列:java.lang.ref.ReferenceQueue,这个引用队列是可以三种引用类型联合使用的,以便跟踪java虚拟机回收所引用对象的活动。

附:相关源码

 /*
* @(#)ReferenceQueue.java 1.23 03/12/19
*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/ package java.lang.ref; /**
* Reference queues, to which registered reference objects are appended by the
* garbage collector after the appropriate reachability changes are detected.
*
* @version 1.23, 12/19/03
* @author Mark Reinhold
* @since 1.2
*/ public class ReferenceQueue<T> { /**
* Constructs a new reference-object queue.
*/
public ReferenceQueue() { } private static class Null extends ReferenceQueue {
boolean enqueue(Reference r) {
return false;
}
} static ReferenceQueue NULL = new Null();
static ReferenceQueue ENQUEUED = new Null(); static private class Lock { };
private Lock lock = new Lock();
private Reference<? extends T> head = null;
private long queueLength = 0; boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
synchronized (r) {
if (r.queue == ENQUEUED) return false;
synchronized (lock) {
r.queue = ENQUEUED;
r.next = (head == null) ? r : head;
head = r;
queueLength++;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(1);
}
lock.notifyAll();
return true;
}
}
} private Reference<? extends T> reallyPoll() { /* Must hold lock */
if (head != null) {
Reference<? extends T> r = head;
head = (r.next == r) ? null : r.next;
r.queue = NULL;
r.next = r;
queueLength--;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(-1);
}
return r;
}
return null;
} /**
* Polls this queue to see if a reference object is available. If one is
* available without further delay then it is removed from the queue and
* returned. Otherwise this method immediately returns <tt>null</tt>.
*
* @return A reference object, if one was immediately available,
* otherwise <code>null</code>
*/
public Reference<? extends T> poll() {
synchronized (lock) {
return reallyPoll();
}
} /**
* Removes the next reference object in this queue, blocking until either
* one becomes available or the given timeout period expires.
*
* <p> This method does not offer real-time guarantees: It schedules the
* timeout as if by invoking the {@link Object#wait(long)} method.
*
* @param timeout If positive, block for up <code>timeout</code>
* milliseconds while waiting for a reference to be
* added to this queue. If zero, block indefinitely.
*
* @return A reference object, if one was available within the specified
* timeout period, otherwise <code>null</code>
*
* @throws IllegalArgumentException
* If the value of the timeout argument is negative
*
* @throws InterruptedException
* If the timeout wait is interrupted
*/
public Reference<? extends T> remove(long timeout)
throws IllegalArgumentException, InterruptedException
{
if (timeout < 0) {
throw new IllegalArgumentException("Negative timeout value");
}
synchronized (lock) {
Reference<? extends T> r = reallyPoll();
if (r != null) return r;
for (;;) {
lock.wait(timeout);
r = reallyPoll();
if (r != null) return r;
if (timeout != 0) return null;
}
}
} /**
* Removes the next reference object in this queue, blocking until one
* becomes available.
*
* @return A reference object, blocking until one becomes available
* @throws InterruptedException If the wait is interrupted
*/
public Reference<? extends T> remove() throws InterruptedException {
return remove(0);
} }

ReferenceQueue

 /*
* @(#)SoftReference.java 1.34 03/12/19
*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/ package java.lang.ref; /**
* Soft reference objects, which are cleared at the discretion of the garbage
* collector in response to memory demand. Soft references are most often used
* to implement memory-sensitive caches.
*
* <p> Suppose that the garbage collector determines at a certain point in time
* that an object is <a href="package-summary.html#reachability">softly
* reachable</a>. At that time it may choose to clear atomically all soft
* references to that object and all soft references to any other
* softly-reachable objects from which that object is reachable through a chain
* of strong references. At the same time or at some later time it will
* enqueue those newly-cleared soft references that are registered with
* reference queues.
*
* <p> All soft references to softly-reachable objects are guaranteed to have
* been cleared before the virtual machine throws an
* <code>OutOfMemoryError</code>. Otherwise no constraints are placed upon the
* time at which a soft reference will be cleared or the order in which a set
* of such references to different objects will be cleared. Virtual machine
* implementations are, however, encouraged to bias against clearing
* recently-created or recently-used soft references.
*
* <p> Direct instances of this class may be used to implement simple caches;
* this class or derived subclasses may also be used in larger data structures
* to implement more sophisticated caches. As long as the referent of a soft
* reference is strongly reachable, that is, is actually in use, the soft
* reference will not be cleared. Thus a sophisticated cache can, for example,
* prevent its most recently used entries from being discarded by keeping
* strong referents to those entries, leaving the remaining entries to be
* discarded at the discretion of the garbage collector.
*
* @version 1.34, 12/19/03
* @author Mark Reinhold
* @since 1.2
*/ public class SoftReference<T> extends Reference<T> { /* Timestamp clock, updated by the garbage collector
*/
static private long clock; /* Timestamp updated by each invocation of the get method. The VM may use
* this field when selecting soft references to be cleared, but it is not
* required to do so.
*/
private long timestamp; /**
* Creates a new soft reference that refers to the given object. The new
* reference is not registered with any queue.
*
* @param referent object the new soft reference will refer to
*/
public SoftReference(T referent) {
super(referent);
this.timestamp = clock;
} /**
* Creates a new soft reference that refers to the given object and is
* registered with the given queue.
*
* @param referent object the new soft reference will refer to
* @param q the queue with which the reference is to be registered,
* or <tt>null</tt> if registration is not required
*
*/
public SoftReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
this.timestamp = clock;
} /**
* Returns this reference object's referent. If this reference object has
* been cleared, either by the program or by the garbage collector, then
* this method returns <code>null</code>.
*
* @return The object to which this reference refers, or
* <code>null</code> if this reference object has been cleared
*/
public T get() {
T o = super.get();
if (o != null) this.timestamp = clock;
return o;
} }

SoftReference

Java中四种引用:强、软、弱、虚引用的更多相关文章

  1. java中强&comma;软&comma;弱&comma;虚引用 以及WeakHahMap

    java中强,软,弱,虚引用  以及WeakHahMap   一:强软引用: 参考:http://zhangjunhd.blog.51cto.com/113473/53092/进行分析   packa ...

  2. java中的强&comma;软&comma;弱&comma;虚引用

    引用的应用场景 我们都知道垃圾回收器会回收符合回收条件的对象的内存,但并不是所有的程序员都知道回收条件取决于指向该对象的引用类型.这正是Java中弱引用和软引用的主要区别. 如果一个对象只有弱引用指向 ...

  3. java中四种引用类型(对象的强、软、弱和虚引用)

    对象的强.软.弱和虚引用在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK 1.2 ...

  4. java中四种引用类型

    java中四种引用类型  今天看代码,里面有一个类java.lang.ref.SoftReference把小弟弄神了,试想一下,接触java已经有3年了哇,连lang包下面的类都不了解,怎么混.后来在 ...

  5. Java中四种引用的区分

    强引用(StrongReference) 强引用就是指在程序代码之中普遍存在的,比如下面这段代码中的object和str都是强引用: 1 2 Object object = new Object(); ...

  6. java中四种引用类型&lpar;转&rpar;

    今天看代码,里面有一个类java.lang.ref.SoftReference把小弟弄神了,试想一下,接触java已经有3年了哇,连lang包下面的类都不了解,怎么混.后来在网上查资料,感觉收获颇多, ...

  7. Java中四种访问权限总结

    一.Java中有四种访问权限, 其中三种有访问权限修饰符,分别为private.public.protected,还有一种不带任何修饰符(default). 1. private: Java语言中对访 ...

  8. java中四种操作(dom、sax、jdom、dom4j)xml方式详解与比较

    1)DOM(JAXP Crimson解析器)     DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在树中寻找特 ...

  9. java中四种操作xml方式的比较

    1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在树中寻找特定信息. ...

随机推荐

  1. PHP 捕捉错误,记录到日志

    register_shutdown_function("shutdown"); define('ERR_LOG_FILE', '/dev/shm/php_log.txt'); if ...

  2. spring学习遇到的问题汇总

    1.spring注解路由方面的误解 我一直以为在web.xml中配置拦截*.action后,在注解路由的时候必须要xxxx.action. 刚才发现,访问的时候xxxx.action,然后@Reque ...

  3. CSS 第四天 多重背景 变形 过渡

    背景原点:background-origin 图片起始位置 border-box包括边框 padding-box边框内 content-box 内容内 **background-repeat 为no- ...

  4. json&lowbar;encode如何防止汉字转义成unicode

    众所周知,json_encode通常会把json中的汉字转义成unicode,但是这并不一定是我们想要的.有时候,我们需要获得汉字形式的json字符串,比如需要获得gbk编码的json字符串(只要把汉 ...

  5. YUI之数组操作

    YUI的构建数组,将类数组转换成真正的数组,从而可以使用数组的所有方法   数组构建 //真正的数组返回1,类数组返回2,其余的返回0 YArray.test = function (obj) { v ...

  6. javascript 可多选的下拉框 multiselect

    首先引用一个写的很好的博客http://www.cnblogs.com/landeanfen/p/5013452.html 我使用的是bootstrap-multiselect,实现功能是 选择下拉框 ...

  7. IntelliJ Idea编译报错:javacTask&colon; 源发行版 1&period;7 需要目标发行版 1&period;7

    1.项目编译时,IntelliJ Idea编译报错:javacTask: 源发行版 1.7 需要目标发行版 1.7很显然是jdk版本冲突,于是查阅资料,作如下修改:File-->Other Se ...

  8. redis安装集群的2种方式

    redis主从只是数据的备份,当主宕机后不会自动切换从为主,需要手动切换从为主. 哨兵就可以自动切换从为主, 当主数据库遇到异常中断服务后,开发者可以通过手动的方式选择一个从数据库来升格为主数据库,以 ...

  9. RestfulAPI超简单入门

    简单入门 REST -- REpresentational State Transfer,英语的直译就是"表现层状态转移" 是目前最流行的 API 设计规范,用于 Web 数据接口 ...

  10. pageadmin CMS网站制作教程&colon;模板中的站点数据调用

    pageadmin CMS网站建设教程:模板中的站点数据调用 1.获取当前站点Id,返回int数字 Html.CurrentSiteId() 2.获取当前站点url地址,返回string字符串 Htm ...