zoukankan      html  css  js  c++  java
  • WeakReference & SoftReference & WeakHashMap

    Reference

    java.lang.ref包下面,继承于Reference类,帮助gc识别对象引用如何处理

    1. FinalReference: 强引用,即 Object obj = new Object(); 不会被强制回收,会引起OutOfMemory异常
    2. WeakReference, 每次gc都会被回收,不会引起OOM
    3. SoftReference,只有内存不够用时,才会被gc回收,不会引起OOM
    4. PhantomReference,不会被回收,会引起OOM,类似强引用。作用是在回收前,放入指定的ReferenceQueue,帮助跟踪

    回收后,reference.get()会返回null指针


    public class Test {
    
    	private static AtomicInteger finalC = new AtomicInteger();
    	public static class Bean {
    		private byte[] bs = new byte[1024];
    		public Bean() {
    			byte b = 1;
    			Arrays.fill(bs, b);
    		}
    		@Override
    		protected void finalize() throws Throwable { 
    			finalC.incrementAndGet();
    		}
    	}
    	
    	private ReferenceQueue<Bean> queue = new ReferenceQueue<Bean>();
    	
    	private void log(String phase) throws Exception {
    		Field f = queue.getClass().getDeclaredField("queueLength");
    		f.setAccessible(true);
    		System.out.println(phase + "~~~, queue length:" + f.get(queue) + ", final num:" + finalC);
    	}
    	
    	public void test() throws Exception {
    		
    		log("before");
    		List<Reference> refs = new ArrayList<Reference>();
    		for(int i = 0; i < 20480; ++i) {
    			refs.add(new WeakReference<Test.Bean>(new Bean(), queue));
    //			refs.add(new SoftReference<Test.Bean>(new Bean(), queue));
    //			refs.add(new PhantomReference<Test.Bean>(new Bean(), queue));
    			if(i % 3000 == 0) {
    				int nullC = 0;
    				for(int j = 0; j < i; ++j) {
    					if(refs.get(j).get() == null) ++nullC;
    				}
    				log("number:" + i + ", null:" + nullC);
    			}
    		}
    		log("2");
    		System.gc();
    		log("3");
    		System.runFinalization();
    		log("4");
    	}
    }
    


    上述程序,跑在-Xmx=10m下,每个Bean > 1k, 循环跑 2048个,大于 20M


    ======   WeakReference

    before~~~, queue length:0, final num:0
    number:0, null:0~~~, queue length:0, final num:0
    number:6000, null:4746~~~, queue length:4746, final num:4230
    number:12000, null:9688~~~, queue length:9688, final num:9688
    number:18000, null:17130~~~, queue length:15985, final num:15853
    2~~~, queue length:17419, final num:18006
    3~~~, queue length:17723, final num:18119
    4~~~, queue length:19539, final num:20480


    在6000个时,内存还未满,此时回收队列中已有4746个item已标识为NULL,并且4230个已经被finanlized


    ===== SoftReference

    before~~~, queue length:0, final num:0
    number:0, null:0~~~, queue length:0, final num:0
    number:6000, null:0~~~, queue length:0, final num:0
    number:12000, null:9197~~~, queue length:9197, final num:9197
    number:18000, null:17722~~~, queue length:17722, final num:17722
    2~~~, queue length:17722, final num:17722
    3~~~, queue length:17722, final num:17722
    4~~~, queue length:17722, final num:20480


    在6000个时,内存未满,jvm不会强制回收SoftReference,直到12000已经超出内存xmx时


    ====== phantomReference

    before~~~, queue length:0, final num:0
    number:0, null:0~~~, queue length:0, final num:0
    number:6000, null:6000~~~, queue length:0, final num:3294
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space


    不会被强制回收,于是OOM



    WeakHashMap

    包含一个类对象成员: private final ReferenceQueue<K> queue = new ReferenceQueue<K>(); (构建Reference可以不指定队列,但map利用被回收ref放入队列的特性,做了特殊处理)
    使用WeakHashMap.Entry extends WeakReference 构建entry: tab[i] = new Entry<K,V>(k, value, queue, h, e);
    Entry即是一个弱指针,弱指向key对象。即weakReference.get() = key。 每次gc的时候,weakReference指向的entry.key为被回收置为空,并且entry将被放入referenceQueue。注意,此时map中的entry对象本事不为空,value不会空,只有key为空。所以直接获取entry是要出NPE的。
    为此,每次获取entry时,需要通过ReferenceQueue清理table中key为null的entry:
    private void expungeStaleEntries() {
    	Entry<K,V> e;
            while ( (e = (Entry<K,V>) queue.poll()) != null) {
                // 将选定被回收的item,从hashmap集合中置空,跳过。防止hashmap返回null entry
            }
        }

    同上面的例子,bean > 1K, 运行在  -Xmx10m下
    private Map<String, Bean> map;
    	
    	public void test() throws Exception {
    		map = new HashMap<String, Test.Bean>();
    //		map = new WeakHashMap<String, Test.Bean>();
    		
    		for(int i = 1; i < 10240; ++i) {
    			map.put(String.valueOf(i), new Bean());
    			if(i%1000 == 0) {
    				int size = 0;
    				int npsize = 0;
    				for(Entry<String, Test.Bean> entry : map.entrySet()) {
    					++size;
    					if(entry.getKey() == null || entry.getValue() == null) {
    						npsize++;
    					}
    				}
    				System.out.println("num: " + i + ", map size:" + size + ", null pointer:" + npsize);
    			}
    		}
    	}

    =============== HashMap 
    num: 1000, map size:1000, null pointer:0
    num: 2000, map size:2000, null pointer:0
    ......
    num: 8000, map size:8000, null pointer:0
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

    =============== WeakHashMap
    num: 1000, map size:1000, null pointer:0
    num: 2000, map size:2000, null pointer:0
    num: 3000, map size:872, null pointer:0
    num: 4000, map size:1872, null pointer:0
    num: 5000, map size:604, null pointer:0
    num: 6000, map size:1604, null pointer:0
    num: 7000, map size:99, null pointer:0
    num: 8000, map size:1099, null pointer:0
    num: 9000, map size:123, null pointer:0
    num: 10000, map size:1123, null pointer:0
    可见,随着内存增加,entry被不停的会收,并且直接在map中被删除,不会留下空指针


  • 相关阅读:
    C#使用枚举方法来实现读取用户电脑中安装的软件
    C#实现窗体阴影效果
    [转]SQLserver字符串分割函数
    [转]WinForm实现win7 Aero磨砂效果介绍
    C#通过鼠标点击panel移动来控制无边框窗体移动
    [转]Table交替行变色 鼠标经过变色 单击变色
    《面向对象程序设计》 三 Calculator 计算器初步
    PAT 1001A+B Format
    大一下学期的自我目标
    《面向对象程序设计》第二次作业
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3087260.html
Copyright © 2011-2022 走看看