1·为什么要用Java引用 2·java引用有哪几种 3·每种引用的特点是什么 4·它们各自的应用场景有哪些
从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期,JVM 是通过垃圾回收器GC对这四种引用做不同的处理,来实现对象生命周期的改变。
1·设计目的:
- 可以让程序员通过代码来决定某一个对象的生命周期
- 更有利于垃圾回收
2·四种引用类型
垃圾回收器,也叫GC,主要有以下特点:
- 1·段落引用- 当对象不在被程序使用的时候,垃圾回收器会将其回收
- 2·垃圾回收器在回收某一个对象的时候,首先会调用该对象的finalize()方法
- 3·GC主要针对堆内存
为了以下四种引用的执行,定义一个finalize类:
package YingYong;
/**
* @author 宋治泽
*/
public class MyReference {
@Override
protected void finalize() {
//finalize 方法,当这个对象被回收的时候,finalize方法会被调用
System.out.println("回收成功");
}
}
1. 强引用
什么是强引用?
++最普通的引用,把一个对象赋值给一个引用变量,这个引用变量就是强引用++
MyReference m = new MyReference();
如果一个对象中有强引用,当JVM内存不够时,JVM宁愿抛出OOM异常也不会对强引用变量进行回收
回收时刻:
- 1·强引用被赋值为null;
- 2·没有了其他的引用关系,超过了引用的作用域
package YingYong;
import java.io.IOException;
/**
* @author 宋治泽
*/
public class NormalReference {
public static void main(String[] args) throws IOException {
//强引用:一个普通的变量,指向一个对象,然后对象引用消失的时候,视为被废弃的对象,属于被回收的范围,该对象的所有成员变量也随之被回收
MyReference m = new MyReference( );
//当m=null没有标注的时候,强引用是不会被回收的
//m=null;
//启用垃圾回收,并不是在main方法里回收垃圾,而是在垃圾回收线程里面,存在一种可能就是垃圾回收线程环没有回收完,
//main方法就已经结束,会看不到结果,所以写下面的代码
System.gc();
System.out.println("回收不成功");
//阻塞一下main方法,如果不写这句代码,整个main方法就会退出
System.in.read();
}
}
2. 软引用
什么是软引用?
++级别仅次于强引用,软引用通过SoftReference类来实现。当JVM堆内存充足时,和我们在内存里面分配一个对象是一样的,但是当有了新的对象往内存里分配,但是内存不足时,软引用就会被回收。++
注意:
软引用用来描述一些有用但是非必须的对象,对于软引用关联着的对象,在系统即将发生内存溢出异常之前,将会把这些对象列入回收的范围进行二次回收,倘若这次回收JVM堆内存不足,才会抛出内存溢出异常。
package YingYong;
/** 软引用 --是个对象
* -Xmx20M jvm堆最大可使用内存20M
* @author 宋治泽*/
public class SoftReference {
public static void main(String[] args) {
//m指向正常的对象SoftReference,在SoftReference中含有一个引用,这个引用是软引用,指向字节数组(内存大小10M)
java.lang.ref.SoftReference<byte[]> m = new java.lang.ref.SoftReference<>(new byte[1024 * 1024 * 10]);
//m = null;
//软引用指向的对象
System.out.println(m.get());
//回收一下
System.gc();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//如果软引用被回收了,那么get是get不到的
System.out.println(m.get());
//再分配一个数组,heap将装不下,这时候系统会垃圾回收,先回收一次,如果不够,会把软引用回收
//这是一个强引用,但是软引用占了内存10M,会导致空间太满而存放不下
//内存12M
byte[] b = new byte[1024 * 1024 * 12];
System.out.println(m.get());
}
}
实际应用
- 适合用于缓存,当我们存放一张图片的时候,当内部够用的时候,对这个图片进行展示,有更重要的文件存储的时候,内存不够了,就可以使用软引用,对图片先进行GC,以便于重要文件的存储
3. 弱引用
什么是弱引用?
++弱引用和软引用类似,只是关键字变成了WeakReference和软引用有所不同的是,弱引用不管内存是不是充足,够不够下一个对象存储,只要发生GC,都会被回收。++
package YingYong;
/** 弱引用遭到GC就会回收
* 弱引用的使用场景:解决某些地方的内存泄漏问题
* @author 宋治泽*/
public class WeakReference {
public static void main(String[] args) {
java.lang.ref.WeakReference<MyReference> m = new java.lang.ref.WeakReference<>(new MyReference());
//拿m的值
System.out.println(m.get());
System.gc();//对弱引用对象进行回收
//继续拿m的值
System.out.println(m.get());
//以上三句代码可以看出,弱引用遇到GC就会被回收
}
}
4. 虚引用
简单概念:
++又叫幻想引用,通过PhantomReference类来实现。++
和其他引用不同的是,虚引用不会决定对象的生命周期,如果一个对象之中有虚引用存在,那么他就和没有任何引用一样,任何时候都可能被垃圾回收器回收。
package YingYong;
import java.lang.ref.ReferenceQueue;
/**
@author 宋治泽
*/
public class PhantomReference {
public static final ReferenceQueue QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
Object o1 = new Object();
// ReferenceQueue<Object> r = new ReferenceQueue<>();
java.lang.ref.PhantomReference<MyReference> m = new java.lang.ref.PhantomReference<>(new Object(),QUEUE);
System.out.println("-----------GC回收前--------------");
System.out.println(o1);
System.out.println(m.get());
System.out.println(QUEUE.poll());
System.out.println("___________________启动GC___________________");
o1 = null;
System.gc();
try {
//确保GC都执行完了
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(o1);
System.out.println(m.get());
System.out.println(QUEUE.poll());
}
}
用途:
主要用来跟踪对象被垃圾回收器回收的活动。
注意事项:
- 虚引用需要和引用队列(ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象的时候,如果发现此时这个对象有虚引用的存在,就会在GC之前,把虚引用加入到与之关联的引用队列当中。
3·总结
| 类型 | 回收时间 | 用途 | 生存时间 |
|---|---|---|---|
| 强引用 | 从来不会 | 对象的一般状态下 | JVM停止运行的时候 |
| 软引用 | 内存不足的时候 | 对象缓存 | 内存不足的时候 |
| 弱引用 | GC时 | 对象缓存 | GC运行之后 |
| 虚引用 | Unkown | 跟踪对象被垃圾回收器回收的活动 | Unkown |