一、强引用
代码:
package top.gabin.concurrent.reference; /** * 强引用 * -XX:+PrintGC -Xms11m -Xmx11m * */ public class StrongReference { public static void main(String[] args) { // 分配10M, byte[] bytes = new byte[1024 * 1024 * 10]; // 使用默认的PN+PO直接oom了 } }
日志:
[GC (Allocation Failure) 1626K->520K(11776K), 0.0008186 secs] [GC (Allocation Failure) 520K->536K(11776K), 0.0010718 secs] [Full GC (Allocation Failure) 536K->392K(11776K), 0.0080720 secs] [GC (Allocation Failure) 392K->392K(11776K), 0.0016596 secs] [Full GC (Allocation Failure) 392K->375K(11776K), 0.0063991 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at top.gabin.concurrent.reference.StrongReference.main(StrongReference.java:12)
原来以为都一样吧,然后试了一把G1垃圾回收器,结果会执行垃圾回收,不会报错
代码:
package top.gabin.concurrent.reference; /** * 强引用 * -XX:+PrintGC -Xms11m -Xmx11m -XX:+UseG1GC */ public class StrongReference { public static void main(String[] args) { // 分配10M, byte[] bytes = new byte[1024 * 1024 * 10]; // 原来以为到不了这里,结果发现G1如果把bytes变量设置为null,会触发垃圾回收,不会直接oom bytes = null; bytes = new byte[1024 * 1024 * 1]; System.out.println(bytes); } }
打印日志:
[GC pause (G1 Humongous Allocation) (young) (initial-mark) 1770K->592K(12M), 0.0027535 secs] [GC concurrent-root-region-scan-start] [GC pause (G1 Humongous Allocation) (young)[GC concurrent-root-region-scan-end, 0.0006785 secs] [GC concurrent-mark-start] 592K->518K(12M), 0.0023798 secs] [GC concurrent-mark-end, 0.0018801 secs] [GC remark, 0.0012885 secs] [GC pause (G1 Evacuation Pause) (young)-- 10M->518K(12M), 0.0070966 secs] [GC cleanup 621K->621K(12M), 0.0004545 secs] [B@60e53b93
参考main方法的二进制码(解析后的)
0 ldc #2 <10485760> 2 newarray 8 (byte) 4 astore_1 5 aconst_null 6 astore_1 7 ldc #3 <1048576> 9 newarray 8 (byte) 11 astore_1 12 getstatic #4 <java/lang/System.out> 15 aload_1 16 invokevirtual #5 <java/io/PrintStream.println> 19 return
二、软应用
应用场景:缓存,不过目前应该比较少用java做缓存
代码:
ackage top.gabin.concurrent.reference; import java.lang.ref.SoftReference; /** * 运行参数:-XX:+PrintGC -Xms11m -Xmx11m -XX:+UseG1GC * 软应用在内存不够用的时候会触发垃圾回收 */ public class SoftReferenceTest { public static void main(String[] args) { SoftReference<byte[]> softReference0 = new SoftReference<>(new byte[1024 * 1024 * 6]); SoftReference<byte[]> softReference1 = new SoftReference<>(new byte[1024 * 1024 * 6]); System.out.println(softReference0.get() + " "); // 空 System.out.println(softReference1.get() + " "); // 不为空,证明内存不够用的时候会被回收 } }
日志:
[GC pause (G1 Humongous Allocation) (young) (initial-mark) 1753K->544K(12M), 0.0027674 secs] [GC concurrent-root-region-scan-start] [GC concurrent-root-region-scan-end, 0.0005636 secs] [GC concurrent-mark-start] [GC concurrent-mark-end, 0.0001255 secs] [GC remark, 0.0017976 secs] [GC cleanup 6688K->6688K(12M), 0.0004628 secs] [GC pause (G1 Humongous Allocation) (young) 6893K->6663K(12M), 0.0053371 secs] [Full GC (Allocation Failure) 6663K->6524K(12M), 0.0046775 secs] [Full GC (Allocation Failure) 6524K->363K(12M), 0.0043229 secs] null [B@60e53b93
注意Full GC触发了两次,第一次是不回收的,第二次才回收的。
三、弱引用
应用场景:ThreadLocal线程变量中,源码还没看太明白,大概就是为了避免内存泄露
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
代码:
package top.gabin.concurrent.reference; import java.lang.ref.WeakReference; /** * 运行参数:-XX:+PrintGC -Xms11m -Xmx11m -XX:+UseG1GC */ public class WeakReferenceTest { public static void main(String[] args) { WeakReference<byte[]> weakReference = new WeakReference<>(new byte[1024 * 1024 * 5]); System.out.println(weakReference.get()); System.gc(); System.out.println(weakReference.get()); } }
日志:
[B@60e53b93 [Full GC (System.gc()) 7033K->399K(12M), 0.0072117 secs] null
四、虚引用
应用场景:目前知道的应该是在jdk中对直接内存进行回收使用,因为直接内存无法直接被垃圾回收器回收,只能通过UNSAFE做内存管理
代码:
package top.gabin.concurrent.reference; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; /** * 运行参数:-XX:+PrintGC -Xms11m -Xmx11m -XX:+UseG1GC */ public class PhantomReferenceTest { public static void main(String[] args) { ReferenceQueue linkedList = new ReferenceQueue<>(); PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1024 * 1024 * 6], linkedList); // 没回收也取不到,是NULL,虚引用的主要作用在于第二个参数,gc之后,ReferenceQueue会有被回收的对象 System.out.println(reference.get()); System.gc(); // 队列里面会有被回收的对象 System.out.println(linkedList.poll()); } }
日志:
[GC pause (G1 Humongous Allocation) (young) (initial-mark) 1753K->552K(12M), 0.0040210 secs] [GC concurrent-root-region-scan-start] [GC concurrent-root-region-scan-end, 0.0009247 secs] [GC concurrent-mark-start] [GC concurrent-mark-end, 0.0000387 secs] [GC remark, 0.0023809 secs] [GC cleanup 6696K->6696K(12M), 0.0006334 secs] [Full GC (System.gc()) 6798K->6524K(12M), 0.0028324 secs] null java.lang.ref.PhantomReference@60e53b93