Java引用之WeakReference和SoftReference

在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();方法,该对象实例也不会被回收(除非发生内存溢出,该对象才会被回收)

发布了532 篇原创文章 · 获赞 2952 · 访问量 247万+

猜你喜欢

转载自blog.csdn.net/dataiyangu/article/details/104785761