写点什么

我看 JAVA 之 引用类型(Reference)

用户头像
awen
关注
发布于: 2021 年 03 月 19 日

注:基于 jdk11

引用类型

  1. 强引用

  2. 软引用

  3. 弱引用

  4. 虚引用

概念

强引用

默认情况下,new 一个对象,并将其引用赋值给一个变量,即为强引用。


import java.util.Arrays;import java.util.Comparator;
public class M {
@Override protected void finalize() { System.out.println("finalize"); } public static void main(String [] args) { int x= Arrays.asList(new Integer[]{1,3,4,5}).stream().max(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1-o2; } }).get(); System.out.println(x); }}
package chapter06;
import java.io.IOException;
/** * 强引用,是默认的引用,也就是强引用。 * 只要有一个引用指向这个对象,那么这个对象就不是垃圾,一定不会被垃圾回收器回收, * 只有没有引用指向它时才会被垃圾回收期择机回收。 */public class T01_NormalReference {
public static void main(String [] args) throws IOException { M m = new M(); System.gc(); m = null; System.out.println("before gc"); System.gc(); System.out.println("after gc"); System.in.read(); }}
复制代码

执行结果如下:

before gc

after gc

finalize

软引用

gc()不会直接回收,只有在需要分配内存不够的情况下被回收

package chapter06;
import java.io.IOException;import java.lang.ref.SoftReference;
/** * 软引用,gc()不会直接回收,只有在需要分配内存不够的情况下被回收 */public class T01_SoftReference {
public static void main(String [] args) throws IOException, InterruptedException { SoftReference<byte []> m = new SoftReference<>(new byte[1024*1024*10]);
System.out.println(m.get());
System.gc(); Thread.sleep(500);
System.out.println(m.get());
byte [] b = new byte[1024*1024*15]; System.out.println(m.get());
}}
复制代码

执行结果如下:

[B@6bdf28bb

[B@6bdf28bb

null

弱引用

引用存在的情况下,只要 gc()直接回收

package chapter06;
import java.io.IOException;import java.lang.ref.SoftReference;import java.lang.ref.WeakReference;
/** * 弱引用,引用存在的情况下,只要gc()直接回收 */public class T01_WeakReference {
public static void main(String [] args) throws IOException, InterruptedException { WeakReference<M> m = new WeakReference<>(new M());
System.out.println(m.get()); System.gc(); System.out.println(m.get());
ThreadLocal tl = new ThreadLocal(); tl.set(new M()); tl.remove();
}}
复制代码

执行结果如下:

chapter06.M@6b71769e

null

finalize

虚引用

虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用必须和 ReferenceQueue 联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的 ReferenceQueue 中。

import java.io.IOException;import java.lang.ref.PhantomReference;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.lang.ref.WeakReference;import java.util.LinkedList;import java.util.List;
/** * 虚引用,get不到 * 作用,管理堆外内存,DirectBuffer * 垃圾回收器,有一个专门的gc回收线程,通过虚引用管理堆外内存 */public class T01_PhantomReference {
public static final List<Object> LIST = new LinkedList<>(); public static final ReferenceQueue queue = new ReferenceQueue();
public static void main(String [] args) throws IOException, InterruptedException { PhantomReference<M> m = new PhantomReference<>(new M(), queue);
new Thread(()->{ while(true) { LIST.add(new byte[1024*1024*10]); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("1" + m.get()); } }).start();
new Thread(() -> { while(true) { Reference reference = queue.poll(); if (reference != null) { System.out.println("2" + reference); } } }).start(); System.in.read();
}}
复制代码

执行结果如下:

1null

1null

1null

1null

1null

1null

1null

1null

finalize

1null

2java.lang.ref.PhantomReference@457582f7

1null

1null

1null

1null

1null

1null

1null

1null

Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space

at chapter06.T01PhantomReference.lambda$main$0(T01PhantomReference.java:26)

at chapter06.T01_PhantomReference$$Lambda$14/0x0000000800066840.run(Unknown Source)

at java.base/java.lang.Thread.run(Thread.java:834)


扩展

ThreadLocalMap

ThreadLocalMap 的 Entry 继承了 WeakReference,且 Entry 的 Key(ThreadLocal)是弱引用。ThrealLocal 其实就是对 ThreadLocalMap 的操作封装。如果 heap 不足,gc 的时候 key 会被回收掉,出现 Entry<null, obj>的情况,等下次 gc 下次回收会把 Entry<null, obj> 回收。所以 ThreadLocal 的正确使用方法是用完要 remove(),避免内存泄漏。

用户头像

awen

关注

Things happen for a reason. 2019.11.15 加入

还未添加个人简介

评论

发布
暂无评论
我看 JAVA 之 引用类型(Reference)