现在的位置: 首页 > 综合 > 正文

Java引用之WeakReference和SoftReference

2018年06月05日 ⁄ 综合 ⁄ 共 2311字 ⁄ 字号 评论关闭

在Java1.2中我们可以发现一个java.lang.ref包,在这个包中我们可以发现有关引用的知识,比如WeakReference弱引用和SoftReference强引用。

弱引用(WeakReference):

        只具有弱引用的对象声明周期更短暂,在垃圾回收期线程扫描它所管辖的内存区域的过程中,一旦发现了只具有若引用的对象,不管当前内存空间是否足够,都会回收它的内存,不过,要注意的是,由于垃圾回收期是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

软引用(SoftReference):

          也称为强引用,如果一个对象只具有软引用,则内存空间足够,垃圾回收期就不会回收它,如果内存空间不足了,就会回收这些对象的内存,如果垃圾回收期没有回收它,该对象就可以被程序使用。

WeakReference和SoftReference的用武之地:

     WeakReference通常用于在某处保存对象的引用,而又不干扰该对对象被GC回收,如:用于Debug、内存监视工具等程序中。因为这类程序一般要求即要观察到对象,又不能影响该对象正常的GC过程。

     SoftReference是强引用,它保存的对象实例,除非JVM即将OutOfMemory,否则不会被GC回收。这个特性使得它特别适合设计对象Cache。对于Cache,我们希望被缓存的对象最好始终常驻内存,但是如果JVM内存吃紧,为了不发生OutOfMemoryError导致系统崩溃,必要的时候也允许JVM回收Cache的内存,待后续合适的时机再把数据重新Load到Cache中。这样可以系统设计得更具弹性。


下面通过一个实例,来展现这两种引用如何保存对象实例的:

User.java:

public class User implements Serializable{

	private static final long serialVersionUID = 1L;
	
	/* 用户id */
	private Integer uid;
	/* 用户名 */
	private String uname;

	public Integer getUid() {
		return uid;
	}

	public void setUid(Integer uid) {
		this.uid = uid;
	}

	public String getUname() {
		return uname;
	}

	public void setUname(String uname) {
		this.uname = uname;
	}

}

WeakReferenceTest.java:

public class WeakReferenceTest {

	public static void main(String[] args) {

		/*创建User对象*/
		User user = new User();
		/*设置username*/
		user.setUname("廖泽民");
		
		/*把对象放在弱引用中*/
		WeakReference<User> weak = new WeakReference<User>(user);
		
		/*把user对象置空,然后再从若引用中取值*/
		user = null;

		int i = 0;

		/*weak.get()表示从引用中取得对象*/
		while (weak.get() != null) {

			System.out.println(String.format("从弱引用中取值: %s, count: %d", weak.get().getUname(), ++i));

			if (i % 10 == 0) {
				System.gc();
				System.out.println("内存回收方法被调用");
			}

			try {
				Thread.sleep(500);
			} catch (Exception e) {

			}
		}
		System.out.println("对象已经被JVM回收");

	}

}

运行的结果:

从运行结果,我们可以发现当把对象实例保存到WeakReference后,再将对象置空,然后从WeakReference中取值,当System.gc()方法被调用后,对象实例也会被回收!

SoftReferenceTest.java:

public class SoftReferenceTest {

	public static void main(String[] args) {

		/* 创建User对象 */
		User user = new User();
		/* 设置用户名 */
		user.setUname("廖泽民");

		/* 创建强引用对象 */
		SoftReference<User> soft = new SoftReference<User>(user);

		/* 把user对象置空,然后再从强引用中取值【注:要先存在引用中再置空,注意顺序啊】 */
		user = null;

		int i = 0;

		while (soft.get() != null) {
			System.out.println(String.format("从强引用中获取对象: %s, count: %d", soft.get().getUname(), ++i));
			if (i % 10 == 0) {
				System.gc();
				System.out.println("内存回收方法被调用!");
			}
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {

			}
		}
		System.out.println("对象已经被JVM回收!");
	}

}

运行结果:

从运行结果(程序不会停止,一直执行)可以发现,我们把对象实例保存到SoftReference中,然后将对象置空,再从SoftReference中取值时,即使显示的调用System.gc();方法,该对象实例也不会被回收(除非发生内存溢出,该对象才会被回收)

抱歉!评论已关闭.