强、软、弱、虚引用学习

Java中根据引用的内存敏感度和GC之间的关系把引用分成了四个级别:强、软、弱、虚

强引用

宁可OutOfMemory也不回收。看下面的代码:

// 用于占位
public class Holder {
	private static final int MB = 1024 * 1024;
	private byte[] holder;
	public Holder() {
		this.holder = new byte[1 * MB];
	}
}
public class RefrenceLeaning {
	public static void main(String[] args) {
		/**
		 * 强引用,宁可内存溢出也不回收
		 * 只有当设置为power=null的时候才会在GC的时候被释放
		 *
		 * 这个引起的问题是,当使用List等有自由内存结构的数据结构时,需要对用过的手工设置为null
		 */

		Holder d1 = new Holder();
		Holder d2 = new Holder();
		Holder d3 = new Holder();
		Holder d4 = new Holder();
		Holder d5 = new Holder();
	}
}

用VM参数:
-verbose:gc -Xms2m -Xmx2m -Xmn1m -XX:SurvivorRatio=8 -XX:+PrintGCDetails

来执行,会发现抛出内存溢出异常。要解决强引用可能带来的内存消耗,办法是使用之后设置为null。这种情况比较适用于使用有自己的内存结构的数据结构时:

比如如下的一个Queue:

class Queue{
	private Object[] data = new Object[24];
	int index = 0;
	public void put(Object o){
		data[index] = o;
		index++;
	}

	public Object getOne(){
		// 这里因为没有设置返回的Object为null,可能会造成内存泄露
		return data[index--];
	}
}

用刚才的Holder来解释一下就是这样子的:

public class RefrenceLeaning {
	public static void main(String[] args) {
		/**
		 * 强引用,宁可内存溢出也不回收
		 * 只有当设置为power=null的时候才会在GC的时候被释放
		 *
		 * 这个引起的问题是,当使用List等有自由内存结构的数据结构时,需要对用过的手工设置为null
		 */

		Holder d1 = new Holder();
		d1 = null;
		Holder d2 = new Holder();
		d2 = null;
		Holder d3 = new Holder();
		Holder d4 = new Holder();
		Holder d5 = new Holder();
	}
}

这样就不会内存溢出了,说明会被回收

更好的办法是使用作用域来隐式的表示引用的失效,如下:

public class RefrenceLeaning {
	public static void main(String[] args) {
		/**
		 * 强引用,宁可内存溢出也不回收
		 * 只有当设置为power=null的时候才会在GC的时候被释放
		 *
		 * 这个引起的问题是,当使用List等有自由内存结构的数据结构时,需要对用过的手工设置为null
		 */

		{
			Holder d1 = new Holder();
			Holder d2 = new Holder();
			Holder d3 = new Holder();
		}
		Holder d4 = new Holder();
		Holder d5 = new Holder();
	}
}

这样也不会内存溢出。

软引用

很有意思的类,  当一个对象只有软引用的时候,内存不足的时候会被GC掉。注意这个只有。如下:

public class ReferencePowser<T> {
	private T t;
	public ReferencePowser(T t) {
		this.t = t;
	}
}
public class RefrenceLeaning {
	public static void main(String[] args) {
	/**
	  * 用作对比, d1在作用域执行完之后是可以被回收的了,但是因为有
<span style="white-space:pre">	</span>  * ReferencePowser的存在,引用还是强的,所以不会被GC。
         **/
             ReferencePowser<Holder> rp1 = null;
    <span style="white-space:pre">	</span>    {
        <span style="white-space:pre">	</span>Holder d1 = new Holder();
       <span style="white-space:pre">		</span>rp1 = new ReferencePowser<Holder>(d1);
    <span style="white-space:pre">	</span>    }
    <span style="white-space:pre">	</span>    Holder d2 = new Holder();
    <span style="white-space:pre">	</span>    SoftReference<Holder> sr2 = new SoftReference<Holder>(d2);
    <span style="white-space:pre">	</span>    Holder d3 = new Holder();
    <span style="white-space:pre">	</span>    Holder d4 = new Holder();
    <span style="white-space:pre">	</span>    Holder d5 = new Holder();
    <span style="white-space:pre">	</span>}
}

这里会出现内存溢出。 因为虽然d1在作用域中,但是还有ReferencePowser中的引用,因此仍然不能GC。 看软引用的情况:

public class RefrenceLeaning {
	public static void main(String[] args) {
		/**
		 * 软引用, 当一个对象只有软引用,内存不足的时候会被GC。
		 *
		 */
		SoftReference<Holder> sr1 = null;
		{
		    Holder d1 = new Holder();
		    sr1 = new SoftReference<Holder>(d1);
		}
		Holder d2 = new Holder();
		SoftReference<Holder> sr2 = new SoftReference<Holder>(d2);
                System.gc();
<span style="white-space:pre">		</span>try {
<span style="white-space:pre">			</span>Thread.sleep(1000);
<span style="white-space:pre">		</span>} catch (InterruptedException e) {
<span style="white-space:pre">			</span>e.printStackTrace();
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>System.out.println("d1=" + sr1.get());
		Holder d3 = new Holder();
		Holder d4 = new Holder();
		Holder d5 = new Holder();
		System.out.println("d1=" + sr1.get());
		System.out.println("d2=" + sr2.get());
	}
}

将会打印如下:

d1=com.price.effective.create.Holder@ca0b6

d1=null
d2=com.price.effective.create.Holder@1b67f74

可见之照样被回收了。  这样就可以实现一些特别的场景。 比如如果这个对象一直内存还够,就不会回收,可以用sr1.get()拿回来,但是内存不够的时候可能需要重新创建。这样可以一定程度的起到缓存的作用。

弱引用

跟软引用的区别在于,只有软引用的时候,只要执行了GC都会被GC掉,不会等到内存不足

public class RefrenceLeaning {
	public static void main(String[] args) {
		/**
		 * 弱引用,只有弱引用的时候,只要进行GC,就会被回收,不会等到内存不够的时候
		 *
		 */
		WeakReference<Holder> wr1 = null;
		{
			Holder d1 = new Holder();
			wr1 = new WeakReference<Holder>(d1);
		}
		Holder d2 = new Holder();
		SoftReference<Holder> sr2 = new SoftReference<Holder>(d2);
		System.gc();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("d1=" + wr1.get());
		Holder d3 = new Holder();
		Holder d4 = new Holder();
		Holder d5 = new Holder();
		System.out.println("d1=" + wr1.get());
		System.out.println("d2=" + sr2.get());
	}
}

打印如下:

d1=null
d1=null
d2=com.price.effective.create.Holder@a62fc3
可以看出来,第一次GC的时候内存还够,但是已经被GC掉了。

虚引用

又叫幽灵引用,很少用到,只有虚引用的时候垃圾回收的时候是根本不会考虑这个引用的,该干啥干啥。

一般跟ReferenceQueue一起实现细粒度的内存控制。 当虚引用的对象GC后,这个虚引用会被放入到queue中,这样可以监控这个queue做一些特别的事情。从网上找到的一段代码很好。用来判断只有当内存回收之后才分配新的对象:

http://blog.csdn.net/imzoer/article/details/8044900

时间: 2025-01-26 20:10:23

强、软、弱、虚引用学习的相关文章

Java中对象的强、软、弱和虚引用

1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么 程序就无法再使用这个对象.也就是说,只有对象处于可触及 (reachable)状态,程序才能使用它.从JDK 1.2版本开始,把对 象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命 周期.这4种级别由高到低依次为:强引用.软引用.弱引用和虚 引用.图1为对象应用类层次. 图1 ⑴强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃 圾回收器绝不会回收

Java:对象的强、软、弱和虚引用

1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期.这4种级别由高到低依次为:强引用.软引用.弱引用和虚引用.图1为对象应用类层次.   图1 ⑴强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内

java-基础-强、软、弱、虚引用

Java的四种引用,强弱软虚,用到的场景. JDK1.2之前只有强引用,其他几种引用都是在JDK1.2之后引入的. 强引用(Strong Reference) 最常用的引用类型,如Object obj = new Object(); .只要强引用存在则GC时则必定不被回收. 软引用(Soft Reference) 用于描述还有用但非必须的对象,当堆将发生OOM(Out Of Memory)时则会回收软引用所指向的内存空间,若回收后依然空间不足才会抛出OOM.一般用于实现内存敏感的高速缓存. 当真

[转]Java对象的强、软、弱和虚引用

转前说明:通常我们在缓存对象的时候可以用到的是软引用,这样java的垃圾回收器在内存紧张时会自动回收一部分这种引用相关的对象,我们也可以考虑直接使用WeakHashMap.转自:http://java.chinaitlab.com/oop/716371_3.html及http://hi.baidu.com/flatworld/blog/item/7b2f3600bde88b83e950cd53.html       在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个

Java中的强引用、软引用、弱引用和虚引用

Java中的强引用.软引用.弱引用和虚引用  原文链接:http://aaronfu.net/?p=9995 从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用. 1.强引用本章前文介绍的引用实际上都是强引用,这是使用最普遍的引用.如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它.当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止

强、软、弱、虚引用例子

下面用更多的例子来说明一下各种引用的用法: 第一个场景:后退 public class LastStep { Holder d = new Holder(); SoftReference<Holder> sr = new SoftReference<Holder>(d); public static void main(String[] args) { } public Holder getHolder(){ if(sr.get() == null){ return new Hol

Java中的软引用,弱引用和虚引用

在Android的图片处理中,碰到的一个非常普遍的问题便是OOM错误 为此网上也有很多例子,而在之前的一篇转载里 提到了ListView中加载图片的ImageLoader,而其中有一处,使用到了名为SoftPreference的类 这是Java中的一个类 也就是所谓的软引用 在查询了相关的资料以后 会发现SoftPreference的特性,非常适合用来处理OOM引起的问题 下面是百度文库的一篇转载: SoftReference.Weak Reference和PhantomRefrence分析和比

对象的四种状态:强、弱、虚、空,哪种会回收?为什么?

问题描述 高手们帮帮忙,这是一道面试题我从来没有听说过对象的这四种状态,有知道的麻烦帮忙解解,万分感谢我的分不多只有用我的真心感谢您了谢谢 解决方案 解决方案二:名词疯狂制造的年代.一般是空对象有机会回收.解决方案三:如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它.当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题.而对于只具有软引用来说,只有当内存不足时,垃圾回收器才会回收

JNI/NDK开发指南(十)——JNI局部引用、全局引用和弱全局引用

转载请注明出处:http://blog.csdn.net/xyang81/article/details/44657385     这篇文章比较偏理论,详细介绍了在编写本地代码时三种引用的使用场景和注意事项.可能看起来有点枯燥,但引用是在JNI中最容易出错的一个点,如果使用不当,容易使程序造成内存溢出,程序崩溃等现象.所以讲得比较细,有些地方看起来可能比较啰嗦,还请轻啪!<Android JNI局部引用表溢出:local reference table overflow (max=512)>这