对象的引用学习笔记
About 3 minjavajava reference
一、对象的强、软、弱、虚引用
1.1 强引用
一个对象被强引用时(只要有引用指向就不会被回收),就算抛出OOM异常也不会被GC回收。
public static void main(String[] args) throws Exception{
// M写finalize方法,在垃圾回收的时候会被调用. 垃圾回收的线程和main主线程那个先执行,不可控。
M m = new M(); // 强引用
m = null;
System.gc(); // 显示调用垃圾回收
System.out.println(m); // 输出 null
System.in.read(); // 阻塞main线程,给垃圾回收线程时间去执行. 如果重写了finalize方法的话,就会执行该方法
}
1.2 软引用
可用来实现内存敏感的高速缓存(堆空间不够的时候,gc会去回收)。
public static void main(String[] args) throws Exception{
// 在内存中,内存中开辟了一块10m的空间。m执行了SoftReference对象,SoftReference软引用指向了10m的内存数据
SoftReference<byte[]> m = new SoftReference<byte[]>(new byte[1024*1024*10]);
System.out.println (m.get()); // 获取对象地址
System.gc();
Thread.sleep(500); // 给gc回收时间
System.out.println(m.get());
// 设置堆空间最大为20m的时候,前面m的软引用已经有10m的数据了。[-Xmx20M]
// 这个时候在new一个硬引用的b有15m,这个时候堆空间不够20m,故gc会把软引用的数据清理掉。
// 在输出m的对象地址就为空
byte[] b = new byte[1024*1024*12];
System.out.println(m.get());
// 软引用特别适合作缓存
}
1.3 弱引用
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java 虚拟机就会把这个弱引用加入到与之关联的引用队列中(只要执行gc就会被回收)。
public static void main(String[] args) {
// 弱引用
WeakReference<M> m = new WeakReference<>(new M());
System.out.println(m.get());
System.gc(); // gc回收时直接回收弱引用
System.out.println(m.get());
}
1.4 虚引用
虚引用主要用来跟踪对象被垃圾回收的活动(一直不会被引用,jvm会使用)
public static void main(String[] args) {
// 用来管理直接内存(在对象被垃圾回收之后会执行一些操作)
// 看m对象有没有指向堆外内存(不归gc管理的),如果后指向,则清理堆外内存。
PhantomReference<M> m = new PhantomReference<>(new M(), QUEUE);
System.out.println(m.get());
new Thread( () -> {
while(true) {
list.add(new byte[1024*1024]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
System.out.println(m.get());
}
}).start();
// 垃圾回收线程
new Thread(()->{
while (true) {
Reference<? extends M> poll = QUEUE.poll();
if(poll != null) {
System.out.println("虚引用被jvm回收" + poll);
}
}
}).start();
}
虚引用与软引用和弱引用的一个区别在于: 虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
对象传值的三种方式:1. 通过方法的参数。2. 通过静态变量。3.通过ThreadLocal
学习网址: https://www.bilibili.com/video/BV1HD4y1Q71y?p=8