强软弱虚引用试验

一、强引用

代码:

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
原文地址:https://www.cnblogs.com/gabin/p/13618691.html