1.强引用
强引用是最普遍的一种引用,我们写的代码,99.9999%都是强引用:
2.软引用
软引用就是把对象用SoftReference包裹一下,当我们需要从软引用对象获得包裹的对象,只要get一下就可以了
特点:
当内存不足,会触发JVM的GC,如果GC后,内存还是不足,就会把软引用的包裹的对象给干掉
也就是只有在内存不足,JVM才会回收该对象。
SoftReference<Student> studentSoftReference=new SoftReference<Student>(new Student());
Student student = studentSoftReference.get();
System.out.println(student);
- 模拟回收软引用
- 设置堆内存最大20M -Xmx20M
public static void main(String[] args) {
SoftReference softReference=new SoftReference(new byte[1024 * 1024 * 10]);
System.out.println(softReference.get());
System.gc();
//手动垃圾回收后,发现内存还足够。所以软引用没有被回收
System.out.println(softReference.get());
//造成内存不足,进行一次垃圾回收。垃圾回收后内存还是不足。就把软引用的回收了
byte[] bytes = new byte[1024 * 1024 * 10];
System.out.println(softReference.get());
}
- 输出结果
3.弱引用
弱引用的使用和软引用类似,只是关键字变成了WeakReference
特点:
弱引用的特点是不管内存是否足够,只要发生GC,都会被回收:
WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1]);
System.out.println(weakReference.get());
System.gc();
System.out.println(weakReference.get());
- 输出结果
4.虚引用
虚引用需要和ReferenceQueue配合一起使用(把对象,和队列都放入虚引用中)
当发生GC,虚引用指向的对象会被回收,并且会这个对象关联的虚引用(就是这个reference )放到ReferenceQueue中
作用:
在回收直接内存的时候,靠的就是这个
- 模拟回收直接内存过程
- 创建一个低级的线程,一直监听虚引用关联的队列
- 一但队列有内容了,就根据队列存的入口地址。去执行相关的方法(释放直接内存)
ReferenceQueue queue = new ReferenceQueue();
PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
System.out.println(reference.get());
public static void main(String[] args) {
ReferenceQueue queue = new ReferenceQueue();
List<byte[]> bytes = new ArrayList<>();
PhantomReference<Test2> reference = new PhantomReference<Test2>(new Test2(),queue);
//这个线程,主要是用来造成堆内容溢出,然后进行垃圾回收
new Thread(() -> {
for (int i = 0; i < 100;i++ ) {
bytes.add(new byte[1024 * 1024]);
}
}).start();
//这个线程一直监听虚引用关联的队列,当队列有东西了,说明虚引用的对象被回收了
new Thread(() -> {
while (true) {
//获取队列里面的内容
Reference poll = queue.poll();
if (poll != null) {
System.out.println("虚引用被回收了:" + poll);
}
}
}).start();
Scanner scanner = new Scanner(System.in);
scanner.hasNext();
}
- 输出结果
5.总结
引用类型 | 被垃圾回收时间 | 用途 | 生存时间 |
---|---|---|---|
强引用 | 从来不会 | 对象的一般状态 | JVM停止运行时终止 |
软引用 | 在内存不足时 | 对象缓存 | 内存不足时终止 |
弱引用 | 在垃圾回收时 | 对象缓存 | gc运行后终止 |
虚引用 | Unknown | Unknown | Unknown |
6.软引用实例
1.简单的说
软引用和弱引用都可以关联一个队列,但不是必须的
当引用的对象被回收时候,他们自己就会被放到队列中
2.实例
功能:
设置堆内存大小 20M
list中循环添加5个 4M大小的byte(byte用SoftReference包裹着)
这样,当内存不足的时候,会把这些内存回收掉(并且把list中的SoftReference也剔除),而不是抛出异常
package cn.itcast.jvm.t2;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
/**
* 演示软引用, 配合引用队列
*/
public class Demo2_4 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) {
List<SoftReference<byte[]>> list = new ArrayList<>();
// 引用队列
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
for (int i = 0; i < 5; i++) {
// 关联了引用队列, 当软引用所关联的 byte[]被回收时,软引用自己会加入到 queue 中去
SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB], queue);
System.out.println(ref.get());
list.add(ref);
System.out.println(list.size());
}
// 从队列中获取无用的 软引用对象,并移除
//poll()返回的就是SoftReference
Reference<? extends byte[]> poll = queue.poll();
while( poll != null) {
list.remove(poll);
poll = queue.poll();
}
System.out.println("===========================");
for (SoftReference<byte[]> reference : list) {
System.out.println(reference.get());
}
}
}
7.弱引用实例
1.用法
和软引用的用法都一样
只是弱引用和软引用之间有差别
2.实例
内存不足时,执行GC,然后弱引用就会被回收一次
package cn.itcast.jvm.t2;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
/**
* 演示弱引用
* -Xmx20m -XX:+PrintGCDetails -verbose:gc
*/
public class Demo2_5 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) {
// list --> WeakReference --> byte[]
List<WeakReference<byte[]>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB]);
list.add(ref);
for (WeakReference<byte[]> w : list) {
System.out.print(w.get()+" ");
}
System.out.println();
}
System.out.println("循环结束:" + list.size());
}
}