强引用
Java中默认声明的就是强引用。
只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了
public class O {
//对象会回收会调用此方法
//平时不要重写,会出现OOM问题
@Override
protected void finalize() throws Throwable {
System.out.println("finalize");
}
}
---------------------------
public class Test {
public static void main(String[] args){
O o = new O(); //强引用
o = null; //置空,new O()就是垃圾了,会被gc回收
System.gc(); //通知虚拟机进行垃圾回收
}
/* 打印结果:
finalize
*/
}
软引用
软引用是用来描述一些非必需但仍有用的对象。
在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。
可以用来存放一些大图片等缓存。
import java.lang.ref.SoftReference;
//测试例子前,先设置一些VM Options参数-Xmx20M,代表堆内存只有20M
public class Test {
public static void main(String[] args){
//软引用,即new SoftReference<byte[]>里面有软引用指向new byte[1024 * 1024 * 10]
SoftReference<byte[]> m = new SoftReference<byte[]>(new byte[1024 * 1024 * 10]);
//拿
// byte[] b = m.get();
System.out.println(m.get()); //没被回收
//回收
System.gc();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(m.get()); //没被回收
//再分配很大的数组,heap内存装不下,系统会自动进行回收,即软引用会被回收
//超出定义的堆内存((10 + 10 = 20) > (20 - 额外的一些占用))
byte[] other = new byte[1024 * 1024 * 10];
System.out.println(m.get()); //被回收
}
/* 打印结果:
[B@14ae5a5
[B@14ae5a5
null
*/
}
弱引用
ThreadLocal的set方法里面的Entry类就用到弱引用,防止内存泄漏。
ThreadLocal set时是Entry(key, value)set进ThreadLocalMap,而Entry是extends WeakReference<ThreadLocal<?>>的,所以当ThreadLocal=null时,GC会把ThreadLocal回收,但是Thread不死,ThreadLocalMap就会一直存在 ,GC把ThreadLocal回收后,ThreadLocalMap还存在一条无用的信息(key没了,value还在),这样就造成了内存泄漏,所以在ThreadLocal使用完成后,请调用remove方法。
import java.lang.ref.WeakReference;
public class Test {
public static void main(String[] args){
WeakReference<byte[]> m = new WeakReference<>(new byte[10]);
System.out.println(m.get());
System.gc();
System.out.println(m.get());
/* 打印
[B@14ae5a5
null
*/
}
}
虚引用
作用是用来管理堆外内存,gc线程。
DirectByteBuffer(jvm管理的对象,关联着堆外内存),如果没有任何引用指向它,得进行回收,如果直接回收对象,那么堆外内存会发生内存泄露;凡是这种,jvm对它挂一个虚引用,如果其被回收,它的对象信息会放在某个队列上(gc有一个线程一直监控着),gc就清理与之对应的堆外内存。
PhantomReference的第二个参数就是对应的队列。
import java.lang.ref.PhantomReference;
public class Test {
public static void main(String[] args){
PhantomReference<byte[]> m = new PhantomReference<>(new byte[10],null);
System.out.println(m.get());
/* 打印
null
*/
}
}