JVM基础知识之Java中四种应用类型

111 阅读2分钟

前言

在Java1.2之前,一个对象只有“已被引用”和“未被引用”,这无法表示某些特殊情况下的对象。比如在内存充足时需要保留而在内存紧张时才需要被被抛弃的一类对象。

所以在Java1.2之后,Java 对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。

四种引用类型

一,强引用

Java中默认声明的就是强引用,比如:

public class Test{

public static void main(String[] args) {
    testStrongReference();
}

private static void testStrongReference() {
    Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收 
    obj = null;//手动置null
}

}

只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了

二,软引用

软引用需要用 SoftReference 类来实现,对于只有软引用的对象来说,当系统内存足够时它 不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。 当我们设置jvm的最大可用内存是3M后运行下程序时。 在for循环中创建了10次大小为1M的byte数组,如果不使用SoftReference类则在运行中会报OutOfMemoryError错误,因为在这种情况下buff是强应用。但使用SoftReference类后当内存不足是会进行垃圾回收并回收了该软引用。

public class TestOOM {

private static List<Object> list = new ArrayList<>();
    
public static void main(String[] args) {
    
     testSoftReference();
}
private static void testSoftReference() {
	for (int i = 0; i < 10; i++) {
		byte[] buff = new byte[1024 * 1024];
		SoftReference<byte[]> sr = new SoftReference<>(buff);
		list.add(sr);
	}
	
	System.gc(); //主动通知垃圾回收
	
	for(int i=0; i < list.size(); i++){
		Object obj = ((SoftReference) list.get(i)).get();
		System.out.println(obj);
	}
}

}

如果我们将上面示例稍微修改一下:

private static void testSoftReference() {

	byte[] buff = null;

	for (int i = 0; i < 10; i++) {
		buff = new byte[1024 * 1024];
		SoftReference<byte[]> sr = new SoftReference<>(buff);
		list.add(sr);
	}

    System.gc(); //主动通知垃圾回收
	
	for(int i=0; i < list.size(); i++){
		Object obj = ((SoftReference) list.get(i)).get();
		System.out.println(obj);
	}

	System.out.println("buff: " + buff.toString());
}

则会buff会因为强引用的存在而无法被回收,从而报出OOM的错误。

三,弱引用

弱引用需要用 WeakReference 类来实现,它比软引用的生存期更短,对于只有弱引用的对象 来说,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。

` private static void testWeakReference() {

	for (int i = 0; i < 10; i++) {
		byte[] buff = new byte[1024 * 1024];
		WeakReference<byte[]> sr = new WeakReference<>(buff);
		list.add(sr);
	}
	
	System.gc(); //主动通知垃圾回收
	
	for(int i=0; i < list.size(); i++){
		Object obj = ((WeakReference) list.get(i)).get();
		System.out.println(obj);
	}
}

`

四,虚引用

虚引用需要 PhantomReference 类来实现,它不能单独使用,必须和引用队列联合使用。虚 引用的主要作用是跟踪对象被垃圾回收的状态。

` public class PhantomReference extends Reference {

/**
 * Returns this reference object's referent.  Because the referent of a
 * phantom reference is always inaccessible, this method always returns
 * <code>null</code>.
 *
 * @return  <code>null</code>
 */
 
public T get() {
    return null;
}
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
    super(referent, q);
}

} `

五,引用队列(ReferenceQueue)

引用队列可以与软引用、弱引用以及虚引用一起配合使用,当垃圾回收器准备回收一个对象时,如果发现它还有引用,那么就会在回收对象之前,把这个引用加入到与之关联的引用队列中去。程序可以通过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就可以在对象被回收之前采取一些必要的措施。