原创文章:java的4种引用类型 – 编程屋
目录
1 前言
java中的4种引用类型,强引用、软引用、弱引用、虚引用。说这4种引用之前,需要先说一下垃圾回收机制中的finalize()方法,
finalize()方法是Object中的方法,它只有一个空的方法体,并且被protected修饰:
当一个java对象被当成垃圾回收的时候,垃圾回收器会负责调用finalize()方法。
2 4种引用类型
2.1 强引用
强引用:一般来讲就是直接被new出来的对象(Object o = new Object();),只要强引用存在,垃圾回收器就不会回收被引用的对象。
为了证明上述结论,可以做以下验证。
1)重写finalize()方法,因为Object中的finalize()方法只有一个空的方法体,不方便进行测试。
public class Person {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize");
}
}
2)测试方法进行测试
public static void main(String[] args) throws IOException {
Person person = new Person();
System.gc();//触发垃圾回收
System.out.println(person);
System.in.read();//阻塞main线程,给垃圾回收线程执行
}
解析:创建一个Person对象,此时是一个强引用,即便是触发了垃圾回收,垃圾回收器也不会回收被引用的对象。
结果输出了person对象地址,并没有输出finalize()方法体中语句。
那如果将该强引用删掉呢(将person置为null就行)
public static void main(String[] args) throws IOException {
Person person = new Person();
person = null;
System.gc();//触发垃圾回收
System.out.println("person:"+person);
System.in.read();//阻塞main线程,给垃圾回收线程执行
}
再次执行,发现该对象被回收掉。
2.2 软引用
软引用:如果一个对象只具有软引用,并且当前虚拟机的内存足够,那么它就不会被垃圾回收器回收,否则就会回收软引用对象。
public static void main(String[] args) {
SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
System.out.println("softReference:"+softReference.get());
System.gc();
try { //进行睡眠让垃圾回收有时间执行
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("softReference:"+softReference.get());
}
分析下以上代码:
SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
创建了一个10m大小的byte对象,放到了软引用对象中,并且有一个softReference对象指向了软引用对象。如下:
为了证明上述所说情况在内存足够的情况下运行。控制台输出如下:
可以发现软引用对象并没有被垃圾回收。但是如果将虚拟机内存最大设置为20M,并且再创建一个10M的字节数组,它还会这样不会被回收吗?
再次创建一个字节数组。
public static void main(String[] args) {
SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
System.out.println("softReference:"+softReference.get());
System.gc();
try { //进行睡眠让垃圾回收有时间执行
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("softReference:"+softReference.get());
byte[] bytes = new byte[1024 * 1024 * 10];
System.out.println("softReference:"+softReference.get());
}
控制台输出:
可以发现此时,软引用对象已经被回收。
由此可以证明如果一个对象只具有软引用,并且当前虚拟机的内存足够,那么它就不会被垃圾回收器回收,否则就会回收软引用对象。
通常软引用用作缓存处理,先从软引用中获取,如果没有获取到,再从缓存中获取。
2.3 虚引用
虚引用:虚引用必须与引用队列(ReferenceQueue)一起使用,当垃圾回收器准备回收一个对象时,如果发现它有虚引用,就会把这个虚引用加入到与之相关联的队列中,然后就可以通过监听引用队列得知虚引用的回收。
private static final List<Object> LIST = new LinkedList<>();
private static final ReferenceQueue<Person> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
PhantomReference<Person> phantomReference = new PhantomReference<>(new Person(), QUEUE);
System.out.println(phantomReference.get()); //null
//设置-Xmx20M,向内存中放置大小
new Thread(()->{
while (true){
LIST.add(new byte[1024 * 1024]);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(phantomReference.get());
}
}).start();
new Thread(()->{
while (true) {
Reference<? extends Person> poll = QUEUE.poll();
if (poll != null ) {
System.out.println("虚引用对象被jvm回收了======="+poll);
}
}
}).start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public class Person {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize");
}
}
代码解析:
1)全局定义一个LIST集合和一个引用队列QUEUE
2)定义一个虚引用对象phantomReference并将测试回收对象Person以及队列放入其中。
3)将虚拟机大小设置最大为20M
4)设置两个线程,一个线程向内存中不断的添加大小(目的是内存满了之后垃圾回收机制回收Person类并将虚引用放入引用队列QUEUE中)另外一个线程是为了测试是否拿到放入队列中的线程。
控制台输出如下:
发现结论是正确的。
2.4 弱引用
以上只是部分内容,为了维护方便,本文已迁移到新地址:java的4种引用类型 – 编程屋