JVM学习之引用类型

Java引入类型

  • 强引用:当内存不足的时候,JVM宁可出现OutOfMemoryError,也不会将内存回收。

    强引用是JVM默认的支持模式,即:在引用期间,如果该堆内存被栈内存所指向,那么该对象无法被GC回收,如果出现内存空间不足,就会抛出 “OutOfMemoryError”。

    public static void main(String[] args) {
        Object o = new Object(); // 强引用
        Object ref = o; // 引用传递
        o = null; // 断开一个引用
        System.gc(); // 手动垃圾回收
        System.out.println(ref);
    }
    
    输出:
    java.lang.Object@3cd1a2f1
  • 软引用:内存不足的时候,进行对象的回收,往往用于高速缓存。

    在许多的开源组件之中,往往会使用软引用作为缓存组件出现,最大的特点就是:内存空间充足时不回收,内存空间不足时回收。

    // 内存充足
    public static void main(String[] args) {
        Object o = new Object();
        SoftReference softReference = new SoftReference(o); // 软引用
        o = null; // 使new Object() 只维护一个软引用
        System.gc(); // 垃圾回收
        System.out.println("软引用:" + softReference.get());
    }
    
    输出:
    软引用:java.lang.Object@3cd1a2f1
    
    /******************************************************/
    
    // 内存不足
    public static void main(String[] args) {
        Object o = new Object();
        SoftReference softReference = new SoftReference(o); // 软引用
        o = null; // 使new Object() 只维护一个软引用
        // 创造大量垃圾,触发GC
        String str = "showSoftRef";
        try {
            for (int i = 0; i < 100; i++) {
                str += str;
                str.intern();
            }
        } catch (Throwable e) {
    
        }
        System.out.println("软引用:" + softReference.get());
    }
    
    输出:
    软引用:null
  • 弱引用:不管内存是否紧张,只要有GC处理,就会被回收。弱引用需要使用的是Map接口的子类:java.util.WeakHashMap。

    public static void main(String[] args) {
        String hello = new String("hello");
        String world = new String("world");
        // 弱引用
        Map<String, String> map = new WeakHashMap<String, String>();
        map.put(hello, world);
        System.out.println(map);
        hello = null; //断开强引用
        System.out.println(map);
        System.gc(); // 垃圾回收
        System.out.println(map);
    }
    
    输出:
    {hello=world}
    {hello=world}
    {}
    
    /******************************************************/
    把上面的WeakHashMap替换成HashMap,输出结果为:
    {hello=world}
    {hello=world}
    {hello=world}
    
    // 因为:HashMap是强引用,不会被回收
    // 为什么项目中不用WeakHashMap而频繁使用HashMap呢?
    // 如果在项目中使用WeakHashMap,当一条线程在取数据的时候,另外一条线程在进行GC,这个容易丢失数据。
    
    /******************************************************/
    public static void main(String[] args) {
        Object o = new Object();
        WeakReference softReference = new WeakReference(o); // 弱引用
        o = null; // 使new Object() 只维护一个弱引用
        System.gc(); // 垃圾回收
        System.out.println("弱引用:" + softReference.get());
    }
    
    输出:
    弱引用:null
  • 幽灵引用(虚引用):永远无法从这个引用中取数据。

    所有保存在幽灵引用中的数据都不会真正的保留。

    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
        PhantomReference softReference = new PhantomReference(o, queue); // 幽灵引用
        // 这里没有断开强引用
        System.gc();
        System.out.println(softReference.get());
        System.out.println(queue.poll());
    }
    
    输出:
    null
    null
  • 引用对列:保存准备被回收的对象。很多时候对象的回收扫描都要从根集合开始,那么对于整个GC而言,要想确定哪些对象可以被回收,就必须确定好引用的强度这个也就是所谓的引用路径设置。
    这里写图片描述

    如果现在要找到对象5,很明显:1 到 5 属于 “强+软”,2 到 5 属于 “强+弱”;软引用要比弱引用保存程度更强。这个时候对于对象的引用而言,如果要进行引用的关联判断,我们就必须找到强关联。为了避免非强引用对象带来的内存引用问题,所以提供引用队列的概念。

    如果在创建软引用或者弱引用类型的时候使用引用队列的方式,那么这个对象被回收之后会自动保存在引用队列之中。

    public static void main(String[] args) throws InterruptedException {
     Object o = new Object();
     ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); // 引用队列
     WeakReference softReference = new WeakReference(o, queue); // 弱引用
     System.out.println(queue.poll());
     o = null; // 断开强引用
     System.gc();
     Thread.sleep(100); // 等待对象被保存到引用队列中
     System.out.println(queue.poll());
    }
    
    输出:
    null
    java.lang.ref.WeakReference@3cd1a2f1

猜你喜欢

转载自blog.csdn.net/qq_34560242/article/details/81044700
今日推荐