java.lang.ref.* 包 提供了引用对象类,支持在某种程度上与垃圾回收器之间的交互。更准确的说是通过引用对象类来窥探对象被垃圾回收器处理的状态。 程序可以使用一个引用对象来维持对另外某一对象的引用,但所采用的方式是使后者仍然可以被回收器在特定的场景下(内存不足,gc操作等)回收。同时程序还可以安排在回收器确定某一给定对象的可到达性已经更改之后的某个时间得到通知(初始化引用对象时 指定引用注册队列ReferenceQueue)。
垃圾回收器可以在特定的情景(或者说分阶段回收)下对对象进行回收。其中的某些特定实现和应用系统的缓存设计是密切相关的,即通过这些对象引用来取对象,但是又保证内存不足的时候,释放内存,当然对象引用是不能获取到其关联的值了。,这也是本文重点关注的。
本文主要从使用和原理的角度来介绍相关概念。
引用的抽象接口
- java.lang.ref.Reference
Reference:字面的含义就是引用,java中的引用 从垃圾回收分期回收的角度,又分为 强引用,软引用,弱引用,虚引用。
构造构造一个具体的Reference 可以传递 一个跟踪 Reference 的 ReferenceQueue ,当具体的Reference ,比如SoftReference 可以到达时,那么ReferenceQueue 中可以取得 这个引用,不可达时候,取不到。这种用法是垃圾回收器标记过此对象后,可以给ReferenceQueue 一个通知,即加入ReferenceQueue 队列,表示当前引用已经到达。这也是程序开发接口可以监控对象引用状态的点。
可达性概念
从最强到最弱,不同的可到达性级别反映了对象的生命周期。在操作上,可将它们定义如下:
如果某一线程可以不必遍历所有引用对象而直接到达一个对象,则该对象是强可到达 对象。新创建的对象对于创建它的线程而言是强可到达对象。
如果一个对象不是强可到达对象,但通过遍历某一软引用可以到达它,则该对象是软可到达 对象。
如果一个对象既不是强可到达对象,也不是软可到达对象,但通过遍历弱引用可以到达它,则该对象是弱可到达 对象。当清除对某一弱可到达对象的弱引用时,便可以终止此对象了。
如果一个对象既不是强可到达对象,也不是软可到达对象或弱可到达对象,它已经终止,并且某个虚引用在引用它,则该对象是虚可到达 对象。
最后,当不能以上述任何方法到达某一对象时,该对象是不可到达 对象,因此可以回收此对象。
下面是Reference 的几个实现
1、强引用,这个是我们普通使用的定义对象的方式。
- java.lang.ref.FinalReference
eg:Object obj = new Object(); 那么obj对heap的Ojbect对象就是一个强引用。
特点:
强引用可以直接访问目标对象。
强引用所指向的对象在任何时候都不会被系统回收。
强引用可能导致内存泄漏。
2、软引用。软引用最主要的特点是对象会在内存不足的情况下才进行回收,所以常用来用作缓存的设计。
- java.lang.ref.SoftReference
特点:
软引用使用 get() 方法取得对象的强引用从而访问目标对象。
软引用所指向的对象按照 JVM 的使用情况(Heap 内存是否临近阈值)来决定是否回收。
软引用可以避免 Heap 内存不足所导致的异常
当垃圾回收器决定对其回收时,会先清空它的 SoftReference,也就是说 SoftReference 的 get() 方法将会返回 null,然后再调用对象的 finalize() 方法,并在下一轮 GC 中对其真正进行回收。
测试:
- import java.lang.ref.Reference;
- import java.lang.ref.ReferenceQueue;
- import java.lang.ref.SoftReference;
- /**
- * test SoftReference useage
- * @author xinchun.wang
- */
- public class SoftReferenceTest {
- public static void main(String[] args) throws InterruptedException {
- A a = new A();
- a.src = "aaa";
- ReferenceQueue<A> rq = new ReferenceQueue<A>();
- SoftReference<A> weak = new SoftReference<A>(a, rq);
- a = null;
- System.out.println(weak.get().src); // exist
- System.gc();
- System.out.println(weak.get().src); // just gc,not use all heap , still exist
- cleanHeapFunction(); //casue use all heap
- System.out.println(weak.get()); // not exist
- Reference<? extends A> rs = rq.poll(); //can get instance
- System.out.println(rs);
- System.out.println(rs.get());
- }
- /**
- * use all heap ,casuse full gc
- */
- public static void cleanHeapFunction(){
- try{
- StringBuffer bf = new StringBuffer();
- for(int i=0;i<10000000000L;i++){
- bf.append(i);
- bf.append(bf);
- }
- }catch(Error e){
- }
- }
- }
3、弱引用。弱引用最主要的特点是对象会在gc的时候立即回收,不考虑内存实际占用。所以在某些短生命周期的对象也是适合做缓存的。
- java.lang.ref.WeakReference
特点:
弱引用使用 get() 方法取得对象的强引用从而访问目标对象。
一旦系统内存回收,无论内存是否紧张,弱引用指向的对象都会被回收。
弱引用也可以避免 Heap 内存不足所导致的异常。
WeakReference 是弱于 SoftReference 的引用类型。弱引用的特性和基本与软引用相似,区别就在于弱引用所指向的对象只要进行系统垃圾回收,不管内存使用情况如何,永远对其进行回收(get() 方法返回 null)。
测试案例1:
- import java.lang.ref.Reference;
- import java.lang.ref.ReferenceQueue;
- import java.lang.ref.WeakReference;
- class A {
- public String src;
- }
- /**
- * @author xinchun.wang */
- public class WeakReferenceTest {
- public static void main(String[] args) throws InterruptedException {
- A a = new A();
- a.src = "aaa";
- ReferenceQueue<A> rq = new ReferenceQueue<A>();
- WeakReference<A> weak = new WeakReference<A>(a, rq);
- a = null; // make a = null ,not use this instance
- System.out.println(weak.get().src); //we also get it,not remove from heap
- System.gc(); //GC
- Thread.sleep(1000);
- Reference<? extends A> rs = rq.poll();
- System.out.println(rs.get()); // rs.get() is null,remove from heap
- }
- }
测试案例2:下面这个程序永远不会抛内存溢出,原理同上。
- package com.qunar.flight.tts.policy.client.validator.impl;
- import java.util.WeakHashMap;
- public class Test {
- public static void main(String[] args) throws Exception {
- WeakHashMap<byte[][], byte[][]> map = new WeakHashMap<byte[][], byte[][]>();
- for (int i = 0; i < 10000000; i++) {
- map.put(new byte[1000][1000], new byte[1000][1000]);
- System.err.println(map.size());
- }
- }
- }
4、虚引用。这个在实际使用中不太普遍。
- java.lang.ref.PhantomReference
PhantomReference 是所有“弱引用”中最弱的引用类型。不同于软引用和弱引用,虚引用无法通过 get() 方法来取得目标对象的强引用从而使用目标对象,观察源码可以发现 get() 被重写为永远返回 null。
值得注意的是,对于引用回收方面,虚引用类似强引用不会自动根据内存情况自动对目标对象回收,Client 需要自己对其进行处理以防 Heap 内存不足异常。
应用举例:
在common-pool 2.x的版本中,提供了ObjectPool的一个实现为:SoftReferenceObjectPool
代码分析如下:
- public class SoftReferenceObjectPool<T> extends BaseObjectPool<T> {
- /** 生成对象的工厂 */
- private final PooledObjectFactory<T> factory;
- /**
- * 引用队列
- */
- private final ReferenceQueue<T> refQueue = new ReferenceQueue<T>();
- /** 被pool的客户端取走的对象总量*/
- private int numActive = 0; // @GuardedBy("this")
- /** 销毁的所有实例的总数 */
- private long destroyCount = 0;
- /** 创建的实例的总数 */
- private long createCount = 0;
- /** 可以被客户端借用的空闲引用对象的引用队列 */
- private final LinkedBlockingDeque<PooledSoftReference<T>> idleReferences =
- new LinkedBlockingDeque<PooledSoftReference<T>>();
- /** 已经被借走或者等待被借走的所有对象引用的引用队列 */
- private final ArrayList<PooledSoftReference<T>> allReferences =
- new ArrayList<PooledSoftReference<T>>();
- /**
- * 构造函数 指定对象创建工厂
- */
- public SoftReferenceObjectPool(PooledObjectFactory<T> factory) {
- this.factory = factory;
- }
- /**
- * client 借用对象
- */
- @Override
- public synchronized T borrowObject() throws Exception {
- assertOpen(); //保证pool 是打开的
- T obj = null;
- boolean newlyCreated = false;
- PooledSoftReference<T> ref = null;
- while (null == obj) {
- if (idleReferences.isEmpty()) { //如果没有空闲的对象引用
- if (null == factory) {
- throw new NoSuchElementException(); //无法生产,直接抛出异常
- } else {
- newlyCreated = true;
- obj = factory.makeObject().getObject();//工厂直接生产一个对象
- createCount++;
- // 包装成PooledSoftReference对象
- ref = new PooledSoftReference<T>(new SoftReference<T>(obj));
- allReferences.add(ref); //加入allReferences ,但是注意:不加入idleReferences!!!
- }
- } else { //如果有空闲的对象
- ref = idleReferences.pollFirst(); //如果空闲有,从空闲里取出来
- obj = ref.getObject(); //对象被强引用
- ref.getReference().clear(); //清空对obj对象引用
- ref.setReference(new SoftReference<T>(obj)); //这样会导致 allReferences 里的 ref 的SoftReference 清空,所以下面需要从新生成一个引用
- }
- if (null != factory && null != obj) {
- try {
- factory.activateObject(ref);
- if (!factory.validateObject(ref)) {
- throw new Exception("ValidateObject failed");
- }
- } catch (Throwable t) {
- PoolUtils.checkRethrow(t);
- try {
- destroy(ref);
- } catch (Throwable t2) {
- PoolUtils.checkRethrow(t2);
- } finally {
- obj = null;
- }
- if (newlyCreated) {
- throw new NoSuchElementException(
- "Could not create a validated object, cause: " +t.getMessage());
- }
- }
- }
- }
- numActive++; //激活数量+1
- ref.allocate(); //设置对象的状态
- return obj;
- }
- /**
- * 归还一个对象
- */
- @Override
- public synchronized void returnObject(T obj) throws Exception {
- boolean success = !isClosed();
- final PooledSoftReference<T> ref = findReference(obj); //找到obj对应的对象引用
- if (ref == null) {
- throw new IllegalStateException("Returned object not currently part of this pool");
- }
- if (factory != null) {
- if (!factory.validateObject(ref)) { //进行验证
- success = false;
- } else {
- try {
- factory.passivateObject(ref);
- } catch (Exception e) {
- success = false;
- }
- }
- }
- boolean shouldDestroy = !success;
- numActive--; //归还后,numActive减少。
- if (success) {
- // Deallocate and add to the idle instance pool
- ref.deallocate();//如果归还成功,那么该ref的状态
- idleReferences.add(ref);//加入idleReferences 列表。
- }
- notifyAll(); // numActive has changed
- if (shouldDestroy && factory != null) { //如果归还失败,那么销魂ref对象
- try {
- destroy(ref);
- } catch (Exception e) {
- // ignored
- }
- }
- }
- /**
- * 让obj失效,即销毁对象
- */
- @Override
- public synchronized void invalidateObject(T obj) throws Exception {
- final PooledSoftReference<T> ref = findReference(obj);
- if (ref == null) {
- throw new IllegalStateException("Object to invalidate is not currently part of this pool");
- }
- if (factory != null) {
- destroy(ref);
- }
- numActive--;
- notifyAll(); // numActive has changed
- }
- /**
- 这个方法主要用于 预加载情况下,加载对象到idle列表。
- 在加入列表前,对象进行 validateObject ,如果失败则:passivateObject。
- */
- @Override
- public synchronized void addObject() throws Exception {
- assertOpen(); //确定池是打开的
- if (factory == null) {
- throw new IllegalStateException("Cannot add objects without a factory.");
- }
- T obj = factory.makeObject().getObject();
- createCount++;
- // Create and register with the queue
- PooledSoftReference<T> ref = new PooledSoftReference<T>(
- new SoftReference<T>(obj, refQueue)); //注意:注册此对象到 refQueue 列表。
- allReferences.add(ref); //加入allReferences列表
- boolean success = true;
- if (!factory.validateObject(ref)) { //验证对象
- success = false;
- } else {
- factory.passivateObject(ref); //验证失败进行
- }
- boolean shouldDestroy = !success;
- if (success) { //如果成功才加入到空闲列表
- idleReferences.add(ref);
- notifyAll(); // numActive has changed
- }
- if (shouldDestroy) { //如果失败,那么idleReferences 和 idleReferences 进行清理ref对象
- try {
- destroy(ref);
- } catch (Exception e) {
- // ignored
- }
- }
- }
- /**
- *返回一个idle对象的数量
- */
- @Override
- public synchronized int getNumIdle() {
- pruneClearedReferences();
- return idleReferences.size();
- }
- /**
- *返回活动的(客户端在用的)数量
- */
- @Override
- public synchronized int getNumActive() {
- return numActive;
- }
- /**
- 清空列表
- */
- @Override
- public synchronized void clear() {
- if (null != factory) {
- Iterator<PooledSoftReference<T>> iter = idleReferences.iterator();
- while (iter.hasNext()) {
- try {
- final PooledSoftReference<T> ref = iter.next();
- if (null != ref.getObject()) { //如果没有销毁,可能此对象已经被垃圾回收器回收!
- factory.destroyObject(ref);
- }
- } catch (Exception e) {
- }
- }
- }
- idleReferences.clear();
- pruneClearedReferences();
- }
- public void close() {
- super.close();
- clear();
- }
- public synchronized PooledObjectFactory<T> getFactory() {
- return factory;
- }
- /**
- * 如果任何对象被垃圾回收器回收,那么wrappers 必须清除其对应的PooledSoftReference 引用。
- */
- private void pruneClearedReferences() {
- // Remove wrappers for enqueued references from idle and allReferences lists
- removeClearedReferences(idleReferences.iterator());
- removeClearedReferences(allReferences.iterator());
- while (refQueue.poll() != null) {
- try {
- _pool.remove(ref);
- } catch (UnsupportedOperationException uoe) {
- // ignored
- }
- }
- }
- private PooledSoftReference<T> findReference(T obj) {
- Iterator<PooledSoftReference<T>> iterator = allReferences.iterator();
- while (iterator.hasNext()) {
- final PooledSoftReference<T> reference = iterator.next();
- if (reference.getObject() != null && reference.getObject().equals(obj)) {
- return reference;
- }
- }
- return null;
- }
- /**
- *
- * 销毁一个对象 依赖于 生成此对象的工厂,另外把对象引用去除。
- */
- private void destroy(PooledSoftReference<T> toDestroy) throws Exception {
- toDestroy.invalidate();
- idleReferences.remove(toDestroy);
- allReferences.remove(toDestroy);
- try {
- factory.destroyObject(toDestroy);
- } finally {
- destroyCount++;
- toDestroy.getReference().clear();
- }
- }
- /**
- * 清空已经被垃圾回收器 清除的对象的对象引用PooledSoftReference
- */
- private void removeClearedReferences(Iterator<PooledSoftReference<T>> iterator) {
- PooledSoftReference<T> ref;
- while (iterator.hasNext()) {
- ref = iterator.next();
- if (ref.getReference() == null || ref.getReference().isEnqueued()) {
- iterator.remove();
- }
- }
- }
- }
相关推荐
Java.lang.ref 包是 Java 类库中的一个重要组成部分,它包含了与垃圾回收机制密切相关的引用类。这些引用类的设计允许开发者在特定条件下控制对象的生命周期,尤其是在处理缓存、大型数据结构或者避免内存泄漏时显得...
java.lang.ref java.lang.reflect java.math java.net java.nio java.nio.channels java.nio.channels.spi java.nio.charset java.nio.charset.spi java.rmi java.rmi.activation java.rmi.dgc java.rmi...
此外,了解`java.lang.ref.Reference`和垃圾收集机制(如可达性分析)也是关键,它们展示了Java内存管理的工作原理。 2. **虚拟机(JVM)内部**:`java.lang.Thread`和`java.lang.Runtime`提供了对JVM内部操作的...
10. **异常处理**:VM应能处理`NoClassDefFoundError`异常,支持`Java.lang.ref.Reference`(包括`WeakReference`),不包含守护线程,允许调用本地库函数(如`exec()`),提供动态堆栈跟踪,增强`StringBuffer`方法...
总结,java.lang.ref 包中的四种引用类型——StrongReference、SoftReference、WeakReference 和 PhantomReference,提供了不同的内存管理策略,适应不同的场景需求。强引用是最常用的引用类型,但在处理大对象或...
##### 3.18 `java.lang.ref` - **用途**:提供引用对象类,支持与垃圾回收器的交互。 - **关键类**:`Reference`, `SoftReference`, `WeakReference` ##### 3.19 `java.lang.reflect` - **用途**:提供用于获取类和...
弱引用通过`java.lang.ref.WeakReference`类表示,即使有弱引用指向对象,只要没有其他强引用,JVM在任何时候都可以回收该对象。这种引用类型在需要临时存储对象,但又不希望影响其生命周期的情况下非常有用。 最后...
- 幻象引用,也称为虚引用,是最弱的引用类型,通过`java.lang.ref.PhantomReference`实现。它不直接指向对象,甚至无法通过幻象引用访问对象。幻象引用的主要用途是在对象被finalize之后,但还没有被垃圾收集之前...
import java.lang.ref.SoftReference; public class SoftReferenceDemo { public static void main(String[] args) { String str = new String("abc"); SoftReference<String> softReference = new ...
在JAVA中,虚引用的使用可以通过PhantomReference类来实现,PhantomReference类继承自java.lang.ref.Reference类,它提供了get()和enqueue()两个方法,get()方法用于获取虚引用的对象实例,enqueue()方法用于将虚...
**java.lang.ref** - **用途**: 引用对象类。 - **关键类**: - `Reference`: 引用类的基类。 - `SoftReference`: 软引用类。 - `WeakReference`: 弱引用类。 #### 20. **java.lang.reflect** - **用途**: ...
see Appendix D: Disabling Cryptographic Algorithms in Java PKI Programmer's Guide and Disabled Cryptographic Algorithms in Java Secure Socket Extension (JSSE) Reference Guide. Various enhancements ...
Java通过`java.lang.ref.SoftReference`类来实现软引用。相比于强引用,软引用提供了一种在内存不足时释放资源的机制,以防止系统崩溃。因此,软引用常用于缓存策略,允许在内存允许的情况下保持缓存,而在内存紧张...
##### java.lang.ref包下的类 - **Reference**:基类,所有引用类型都继承自该类。 - **PhantomReference**(虚引用):仅用于跟踪垃圾回收过程,不决定对象的生命期。 - **SoftReference**(软引用):当系统即将...
Java使用`java.lang.ref.SoftReference`类来表示软引用。 - 当内存空间不足时,JVM会回收软引用关联的对象,以防止`OutOfMemoryError`的发生。软引用常用于实现缓存,如网页缓存和图片缓存,以便在内存紧张时自动...
Java中的弱引用具体指的是java.lang.ref.WeakReference类,我们首先来看一下官方文档对它做的说明: 弱引用对象的存在不会阻止它所指向的对象变被垃圾回收器回收。弱引用常见的用途是实现规范映射...
软引用(Soft Reference)的主要特点是具有较强的引用功能。只有当内存不够的时候才回收这类内存,因此在内存... import java.lang.ref.SoftReference; public class softReference { /** * @param args *
JVM 垃圾收集对不同...这种交互方式是使用JDK1.2 引入的 java.lang.ref包。 强引用(strong reference) 在一般的 Java 程序中,见到多的是强引用(strong reference)。如 Date date = newDate(),date 是
在Java中,`java.lang.ref`包提供了三种不同类型的引用:强引用(Strong Reference)、软引用(Soft Reference)和弱引用(Weak Reference)。我们主要关注弱引用,它通过`WeakReference`类来实现。弱引用对象在创建...
软引用通过`java.lang.ref.SoftReference`类实现。 - 示例代码:`SoftReference<String> softRef = new SoftReference(new String("Soft Reference"));` 3. **弱引用(Weak Reference)**: - 弱引用比软引用更弱...