引用

強引用

就是GcRoots對象,是棧、方法區、本地裏面引用指向對象,比如 A a=new A();

軟引用

就是該引用的對象可有可無,只要不OOM是不會清除的,在內存溢出之前纔會納入gc範圍。軟引用一般用於一些計算結果和不需要實時獲取的用戶本身或者行爲數據。

現在有redis之類的緩存了,一般情況下是用不到軟引用去維護用戶信息,比如幾個業務需要看用戶是否購買過第二單,你用軟引用是不穩定的服務器重啓就沒了。但是有些應用場景是可以的,就比如A接口產生了一個“結果”,馬上調用B接口而B接口不想重新計算那就可以用軟引用,這個就沒必要去用緩存因爲B接口用完了這個“結果”就沒有意義了/。對於這種“朝生夕死”的結果來說就可以用了,用緩存反而複雜了。

jvm參數

-Xms5m -Xmx5m
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;

public class SoftReferenceHouse {
    public static void main(String[] args) {
    	//List<SoftReference> houses = new ArrayList<>();//註釋1
        List<SoftReference> houses = new ArrayList<>();

        int i = 0;
        while (true) {
            House h = new House();
            SoftReference<House> buyer2 = new SoftReference<>(h);
            houses.add(buyer2);
            //houses.add(h);//註釋2
            System.out.println("i=" + (++i));
        }
    }
}

class House {
    private static final Integer DOOR_NUMBER = 524288;
    private int[] doors = new int[DOOR_NUMBER];
}

執行了就會看到i會變得很大之後還不會出現OOM,最後只會報出GC太頻繁。把註釋1和2替代軟引用很快就會OOM

import java.lang.ref.SoftReference;

public class SoftReferenceWhenIdle {
    public static void main(String[] args) {
        House h = new House();
        SoftReference<House> buyer2 = new SoftReference<House>(h);
        h = null;
        while (true) {
            System.gc();
            System.runFinalization();

            if (buyer2.get() == null) {
                System.out.println("house is null");
                break;
            } else {
                System.out.println("still there");
            }
        }
    }
}

執行會發現會打印很久still there因爲軟引用會挾持對象,除非內存不充足了。

弱引用

弱引用比前兩者對對象的劫持能力更弱,如果對象只剩下弱引用這條路,那麼在下一次YGC時就會被回收,但是YGC時間不確定,所以要注意WeakRefrence.get()會null。

jvm參數

-Xms5m -Xmx5m -XX:+PrintGCDetails
import java.lang.ref.WeakReference;

public class WeakReferenceWhenIdle {
    public static void main(String[] args) {
        House h = new House();
        WeakReference<House> buyer3 = new WeakReference<>(h);
        h = null;
        long currentTimeMillis = System.currentTimeMillis();
        int count = 0;
        while (true) {
            if (buyer3.get() == null) {
                long duration = System.currentTimeMillis() - currentTimeMillis;
                System.out.println("house is null and exited time=" + duration + "ms");
                break;
            } else {
                System.out.println("still there. count=" + (count++));
            }
        }
    }

    static class House {
        private static final Integer DOOR_NUMBER = 262144;
        private int[] doors = new int[DOOR_NUMBER];
    }
}

打印

still there. count=2870
[GC (Allocation Failure) [PSYoungGen: 1515K->320K(1536K)] 4200K->3344K(5632K), 0.0006251 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
still there. count=2871
house is null and exited time=30ms
Heap
 PSYoungGen      total 1536K, used 349K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
  eden space 1024K, 2% used [0x00000000ffe00000,0x00000000ffe07728,0x00000000fff00000)
  from space 512K, 62% used [0x00000000fff00000,0x00000000fff50000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 4096K, used 3024K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000)
  object space 4096K, 73% used [0x00000000ffa00000,0x00000000ffcf40a8,0x00000000ffe00000)
 Metaspace       used 3397K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 362K, capacity 388K, committed 512K, reserved 1048576K

WeakHashMap比較常用到,key一般是"主體" value一般是”主題的附屬“,這樣就能實現主體被ygc後附屬也自動清除。

import java.util.WeakHashMap;

public class WeakHashMapTest {
    public static void main(String[] args) {
        House seller1 = new House("1號賣家房源");
        SellerInfo sellerInfo1 = new SellerInfo();

        House seller2 = new House("2號賣家房源");
        SellerInfo sellerInfo2 = new SellerInfo();
        WeakHashMap<House, SellerInfo> weakHashMap = new WeakHashMap<>();
        weakHashMap.put(seller1, sellerInfo1);
        weakHashMap.put(seller2, sellerInfo2);

        System.out.println("weakHashMap before null.size" + weakHashMap.size());
        seller1 = null;
        System.gc();
        System.runFinalization();
        System.out.println("weakHashMap after null.size" + weakHashMap.size());
        System.out.println(weakHashMap);
    }

    static class House {
        private String house;

        House(String house) {
            this.house = house;
        }
    }

    static class SellerInfo {
        private int info;
    }
}

打印結果

weakHashMap before null.size2
weakHashMap after null.size1
{WeakHashMapTest$House@532760d8=WeakHashMapTest$SellerInfo@57fa26b7}

這個是怎麼實現的呢?大概看下size的源代碼

    public int size() {
        if (size == 0)
            return 0;
        expungeStaleEntries();
        return size;
    }
/**
     * Expunges stale entries from the table.
     */
    private void expungeStaleEntries() {
        for (Object x; (x = queue.poll()) != null; ) {
            synchronized (queue) {
                @SuppressWarnings("unchecked")
                    Entry<K,V> e = (Entry<K,V>) x;
                int i = indexFor(e.hash, table.length);

                Entry<K,V> prev = table[i];
                Entry<K,V> p = prev;
                while (p != null) {
                    Entry<K,V> next = p.next;
                    if (p == e) {
                        if (prev == e)
                            table[i] = next;
                        else
                            prev.next = next;
                        // Must not null out e.next;
                        // stale entries may be in use by a HashIterator
                        e.value = null; // Help GC
                        size--;
                        break;
                    }
                    prev = p;
                    p = next;
                }
            }
        }
    }

主要是queue,看下queue是啥時放入元素的,大概看了下就是在回收的時候。

虛引用

虛引用對對象沒有任何挾持,甚至不能通過虛引用get對象,對一個對象設置虛引用的唯一目的就是在垃圾回收的時候收到一個系統通知。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章