强、软、弱、虚引用学习

简介: <p>Java中根据引用的内存敏感度和GC之间的关系把引用分成了四个级别:强、软、弱、虚</p> <h2>强引用</h2> <div>宁可OutOfMemory也不回收。看下面的代码:</div> <div><pre code_snippet_id="559687" snippet_file_name="blog_20141223_1_5988979" name="code" cl

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


相关文章
|
5月前
|
存储 缓存 算法
(五)JVM成神路之对象内存布局、分配过程、从生至死历程、强弱软虚引用全面剖析
在上篇文章中曾详细谈到了JVM的内存区域,其中也曾提及了:Java程序运行过程中,绝大部分创建的对象都会被分配在堆空间内。而本篇文章则会站在对象实例的角度,阐述一个Java对象从生到死的历程、Java对象在内存中的布局以及对象引用类型。
131 8
|
6月前
|
存储 Swift
Swift开发——弱占用
Swift的自动引用计数(ARC)管理类实例内存,通过强引用保持实例存活。当出现强引用循环时,可使用`weak`关键字创建弱引用,避免阻止实例释放。弱引用在不再被强引用时导致对象立即释放。示例中,添加`weak`至`author`和`book`变量防止引用循环,使得两者析构器均执行,释放内存。图2展示了弱引用结构,当解除所有强引用后,ARC自动释放实例,调用析构器。
209 1
Swift开发——弱占用
|
5月前
|
缓存
线程操纵术并行策略问题之工作窃取机制问题如何解决
线程操纵术并行策略问题之工作窃取机制问题如何解决
|
6月前
|
Java 程序员
理解强引用:在编程中的作用和风险
理解强引用:在编程中的作用和风险
45 0
|
7月前
|
缓存 算法 JavaScript
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
137 0
|
7月前
|
存储 算法 安全
清除你的烦恼!深入探讨垃圾回收算法、垃圾回收器和空间分配担保策略
清除你的烦恼!深入探讨垃圾回收算法、垃圾回收器和空间分配担保策略
|
Java
强、软、弱、虚,你是哪一种?
强、软、弱、虚,你是哪一种?
62 0
|
存储 监控 安全
ThreadLocal之强、弱、软、虚引用(下)
ThreadLocal之强、弱、软、虚引用
ThreadLocal之强、弱、软、虚引用(下)
|
缓存 安全 Java
ThreadLocal之强、弱、软、虚引用(上)
ThreadLocal之强、弱、软、虚引用
ThreadLocal之强、弱、软、虚引用(上)
|
Java
强、软、弱、虚引用
强、软、弱、虚引用
92 0