Java 强引用、 软引用、 弱引用、虚引用
也就是说,仅仅有对象处于可触及(reachable)状态。程序才干使用它。从JDK 1.2版本号開始,把对象的引用分为4种级别。从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。下图为对象应用类层次。
仅仅要垃圾回收器没有回收它。该对象就能够被程序使用。软引用可用来实现内存敏感的快速缓存(下文给出演示样例)。
弱引用与软引用的差别在于:仅仅具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了仅仅具有弱引用的对象,无论当前内存空间足够与否,都会回收它的内存。
只是,因为垃圾回收器是一个优先级非常低的线程,因此不一定会非常快发现那些仅仅具有弱引用的对象。
|
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
|
假设程序发现某个虚引用已经被增加到引用队列,那么就能够在所引用的对象的内存被回收之前採取必要的行动。
由此带来了一个问题,那就是某个对象的可及性怎样推断:
作为一个用户,我们全然有可能须要回头去查看几分钟甚至几秒钟前查看过的雇员档案信息(相同。我们在浏览WEB页面的时候也常常会使用“后退”button)。这时我们一般会有两种程序实现方式:一种是把过去查看过的雇员信息保存在内存中,每个存储了雇员档案信息的Java对象的生命周期贯穿整个应用程序始终;还有一种是当用户開始查看其它雇员的档案信息的时候,把存储了当前所查看的雇员档案信息的Java对象结束引用。使得垃圾收集线程能够回收其所占用的内存空间,当用户再次须要浏览该雇员的档案信息的时候,又一次构建该雇员的信息。非常显然。第一种实现方法将造成大量的内存浪费,而另外一种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包括雇员档案信息的对象仍然完善地保存在内存中。应用程序也要又一次构建一个对象。我们知道,訪问磁盘文件、訪问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,假设能又一次获取那些尚未被回收的Java对象的引用,必将降低不必要的訪问,大大提高程序的执行速度。
也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。
另外,一旦垃圾线程回收该Java对象之后,get()方法将返回null。
|
MyObject aRef = new MyObject();
SoftReference aSoftRef=new SoftReference(aRef);
|
|
aRef = null;
|
Java虚拟机的垃圾收集线程对软可及对象和其它一般Java对象进行了差别对待:软可及对象的清理是由垃圾收集线程依据其特定算法依照内存需求决定的。也就是说,垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软可及对象,并且虚拟机会尽可能优先回收长时间闲置不用的软可及对象,对那些刚刚构建的或刚刚使用过的“新”软可反对象会被虚拟机尽可能保留。在回收这些对象之前,我们能够通过:
|
MyObject anotherRef=(MyObject)aSoftRef.get();
|
假设在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为參数提供给SoftReference的构造方法,如:
|
ReferenceQueue queue = new ReferenceQueue();
SoftReference ref=new SoftReference(aMyObject, queue);
|
也就是说,ReferenceQueue中保存的对象是Reference对象,并且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也能够看出,它是一个队列,当我们调用它的poll()方法的时候。假设这个队列中不是空队列,那么将返回队列前面的那个Reference对象。
假设队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。利用这种方法。我们能够检查哪个SoftReference所软引用的对象已经被回收。于是我们能够把这些失去所软引用的对象的SoftReference对象清除掉。经常使用的方式为:
|
SoftReference ref = null;
while ((ref = (EmployeeRef) q.poll()) != null) {
// 清除ref
}
|
|
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;
getDataFromlnfoCenter();
}
// 到数据库中取得雇员信息
private void getDataFromlnfoCenter() {
// 和数据库建立连接井查询该雇员的信息,将查询结果赋值
// 给name,department。plone,salary等变量
// 同一时候将origin赋值为"From DataBase"
}
……
|
以下是一个对Employee对象进行缓存的缓存器的定义:
|
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Hashtable;
public class EmployeeCache {
static private EmployeeCache cache;// 一个Cache实例
private Hashtable<String,EmployeeRef> employeeRefs;// 用于Chche内容的存储
private ReferenceQueue<Employee> q;// 垃圾Reference的队列
// 继承SoftReference,使得每个实例都具有可识别的标识。
// 而且该标识与其在HashMap内的key同样。
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<String,EmployeeRef>();
q = new ReferenceQueue<Employee>();
}
// 取得缓存器实例
public static EmployeeCache getInstance() {
if (cache == null) {
cache = new EmployeeCache();
}
return cache;
}
// 以软引用的方式对一个Employee对象的实例进行引用并保存该引用
private void cacheEmployee(Employee em) {
cleanCache();// 清除垃圾引用
EmployeeRef ref = new EmployeeRef(em, q);
employeeRefs.put(em.getID(), ref);
}
// 根据所指定的ID号,又一次获取对应Employee对象的实例
public Employee getEmployee(String ID) {
Employee em = null;
// 缓存中是否有该Employee实例的软引用。假设有。从软引用中取得。
if (employeeRefs.containsKey(ID)) {
EmployeeRef ref = (EmployeeRef) employeeRefs.get(ID);
em = (Employee) ref.get();
}
// 假设没有软引用。或者从软引用中得到的实例是null,又一次构建一个实例,
// 并保存对这个新建实例的软引用
if (em == null) {
em = new Employee(ID);
System.out.println("Retrieve From EmployeeInfoCenter. ID=" + ID);
this.cacheEmployee(em);
}
return em;
}
// 清除那些所软引用的Employee对象已经被回收的EmployeeRef对象
private void cleanCache() {
EmployeeRef ref = null;
while ((ref = (EmployeeRef) q.poll()) != null) {
employeeRefs.remove(ref._key);
}
}
|
Java 强引用、 软引用、 弱引用、虚引用的更多相关文章
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
- Java:对象的强、软、弱、虚引用
转自: http://zhangjunhd.blog.51cto.com/113473/53092 1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无 ...
- Java中四种引用:强、软、弱、虚引用
这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...
- Java:对象的强、软、弱和虚引用
1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK ...
- Java对象的强、软、弱和虚引用详解
1.对象的强.软.弱和虚引用 转自:http://zhangjunhd.blog.51cto.com/113473/53092/ 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无 ...
- java基础知识再学习--集合框架-对象的强、软、弱和虚引用
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://zhangjunhd.blog.51cto.com/113473/53092 本文 ...
- Java对象的强、软、弱和虚引用原理+结合ReferenceQueue对象构造Java对象的高速缓存器
//转 http://blog.csdn.net/lyfi01/article/details/6415726 1.Java对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变 ...
- Java:对象的强、软、弱和虚引用[转]
原文链接:http://zhangjunhd.blog.51cto.com/113473/53092/ 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...
- Java对象的强、软、弱和虚引用+ReferenceQueue
Java对象的强.软.弱和虚引用+ReferenceQueue 一.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内存空间不足 ...
- Java:对象的强、软、弱和虚引用的区别
1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK ...
随机推荐
- 浅析SDWebImage
浅析SDWebImage 在日常的开发过程中,如果去优雅的访问网络的图片并去管理每个工程必须要面对的问题,如果想要在工程里面提供易用.简洁.方便管理的解决方案还是很有挑战的,毕竟还要兼顾图片文件的缓存 ...
- 浅谈 PHP 中的多种加密技术及代码示例
信息加密技术的分类 单项散列加密技术(不可逆的加密) 属于摘要算法,不是一种加密算法,作用是把任意长的输入字符串变化成固定长的输出串的一种函数 MD5 string md5 ( string $str ...
- JAVA基础(一) ——— static 关键字
1. 静态代码块 保证只创建一次,提升属性的级别为类变量.初始化后独自占用一块内存 2. 静态代码块执行触发条件 (1).当创建这个类的实例 (2).当调用这个类的静态变量 (3).当调用这个类的 ...
- python数据库操作——sqlite3模块
# -*- coding: utf-8 -*- ''' Version : Python27 Author : Spring God Date : 2012-4-26 ''' import sqlit ...
- jProfiler远程连接Linux监控jvm的运行状态
第一步:下载软件官网地址:https://www.ej-technologies.com/download/jprofiler/files,下载一个linux服务端,一个windows客户端 GUI界 ...
- Android Studio2.3.3卡在Building 'xxx' Gradle project info的解决方法
Android Studio版本:V2.3.3 操作系统环境:Ubuntu14.04 64bit 新安装好Android Studio后,在创建新的项目时或者在导入他人的项目代码时,Android ...
- GCC 4.9.0 公布,提升 C++11 和 C++14 特性
from :http://www.oschina.net/news/51084/gcc-4-9-0 GCC 4.9.0 公布,此版本号是个主要版本号更新,包含了 GCC 4.8.x 系列和之前的 GC ...
- Android设备运用Clockworkmod Recovery恢复模式安装定制的Rom
Clockworkmod Recovery是一个由Cyanogen团队开发的用于Android设备的第三方定制Recovery恢复模式,也称为CWM Recovery,具体它有什么用处呢?请看关于Go ...
- SILICA Xynergy-M4 Board -- STM32F417 meets XILINX Spartan-6
The SILICA Xynergy-M4 Board combines an ARM Cortex-M4 based STMicroelectronics STM32F417 controller ...
- 记录一次软件Bug发生的过程
结束一周的紧张工作,难得的休息时光,坐在电脑前浏览博客.听听歌.看看大片,这也算是一种享受. 因为年度的开发任务已经开始了,所以最近会特别忙,新人的成长又没有想象中的好,经常在他们身上看到自己去年的影 ...