2、 GC 对弱引用的发现和释放也不是立即的,有时需要重复几次 GC ,才会发现并释放弱引用的内存对象 。3、软引用和弱引用在添加到 ReferenceQueue 的时候,其指向真实内存的引用已经被置为空了,相关的内存也已经被释放掉了 。而虚引用在添加到 ReferenceQueue 的时候,内存还没有释放,仍然可以对其进行访问 。
代码示例
通过以上的介绍,相信您对Java 的引用机制以及几种引用方式的异同已经有了一定了解 。光是概念,可能过于抽象,下面我们通过一个例子来演示如何在代码中使用 Reference 机制 。
String str=newString( " hello " );// ①ReferenceQueue < String >rq=newReferenceQueue < String > ();// ②WeakReference < String >wf=newWeakReference < String > (str, rq);// ③str = null ;// ④取消"hello"对象的强引用String str1 = wf.get();// ⑤假如"hello"对象没有被回收,str1引用"hello"对象// 假如"hello"对象没有被回收,rq.poll()返回nullReference <?extendsString >ref = rq.poll();// ⑥在以上代码中,注意⑤⑥两处地方 。假如“hello ”对象没有被回收 wf.get() 将返回“ hello ”字符串对象,rq.poll() 返回 null ;而加入“ hello ”对象已经被回收了,那么 wf.get() 返回 null ,rq.poll() 返回 Reference 对象,但是此 Reference 对象中已经没有 str 对象的引用了 ( PhantomReference 则与WeakReference 、 SoftReference 不同 ) 。
引用机制与复杂数据结构的联合应用了解了GC 机制、引用机制,并配合上 ReferenceQueue ,我们就可以实现一些防止内存溢出的复杂数据类型 。
例如,SoftReference 具有构建 Cache 系统的特质,因此我们可以结合哈希表实现一个简单的缓存系统 。这样既能保证能够尽可能多的缓存信息,又可以保证 Java 虚拟机不会因为内存泄露而抛出 OutOfMemoryError。这种缓存机制特别适合于内存对象生命周期长,且生成内存对象的耗时比较长的情况,例如缓存列表封面图片等 。对于一些生命周期较长,但是生成内存对象开销不大的情况,使用WeakReference 能够达到更好的内存管理的效果 。
附SoftHashmap 的源码一份,相信看过之后,大家会对 Reference 机制的应用有更深入的理解 。
packagecom. *** .widget;// : SoftHashMap.javaimportjava.util. * ;importjava.lang.ref. * ;importAndroid.util.Log;publicclassSoftHashMapextendsAbstractMap{/**The internal HashMap that will hold the SoftReference.*/privatefinalMap hash=newHashMap();/**The number of "hard" references to hold internally.*/privatefinalintHARD_SIZE;/**The FIFO list of hard references, order of last access.*/privatefinalLinkedList hardCache=newLinkedList();/**Reference queue for cleared SoftReference objects.*/privateReferenceQueue queue=newReferenceQueue();// Strong Reference numberpublicSoftHashMap(){this ( 100 ); }publicSoftHashMap( inthardSize){ HARD_SIZE=hardSize; }publicObject get(Object key){Object result=null ;//We get the SoftReference represented by that keySoftReference soft_ref=(SoftReference)hash.get(key);if(soft_ref!=null ){//From the SoftReference we get the value, which can be//null if it was not in the map, or it was removed in//the processQueue() method defined belowresult=soft_ref.get();if(result==null ){//If the value has been garbage collected, remove the//entry from the HashMap.hash.remove(key);}else{//We now add this object to the beginning of the hard//reference queue.One reference can occur more than//once, because lookups of the FIFO queue are slow, so//we don't want to search through it each time to remove//duplicates.// keep recent use object in memoryhardCache.addFirst(result);if(hardCache.size()>HARD_SIZE){//Remove the last entry if list longer than HARD_SIZEhardCache.removeLast();}}}returnresult;}/**We define our own subclass of SoftReference which containsnot only the value but also the key to make it easier to findthe entry in the HashMap after it's been garbage collected.*/privatestaticclassSoftValueextendsSoftReference{privatefinalObject key;//always make data member final/**Did you know that an outer class can access private datamembers and methods of an inner class?I didn't know that!I thought it was only the inner class who could access theouter class's private information.An outer class can alsoaccess private members of an inner class inside its innerclass.*/privateSoftValue(Object k, Object key, ReferenceQueue q){super (k, q);this .key=key;}}/**Here we go through the ReferenceQueue and remove garbagecollected SoftValue objects from the HashMap by looking themup using the SoftValue.key data member.*/publicvoidprocessQueue(){SoftValue sv;while((sv=(SoftValue)queue.poll())!=null ){if (sv.get() ==null ) {Log.e( " processQueue " ," null " );} else {Log.e( " processQueue " ," Not null " );}hash.remove(sv.key);//we can access private data!Log.e( " SoftHashMap " ," release"+sv.key);}}/**Here we put the key, value pair into the HashMap usinga SoftValue object.*/publicObject put(Object key, Object value){processQueue();//throw out garbage collected values firstLog.e( " SoftHashMap " ," put into"+key);returnhash.put(key,newSoftValue(value, key, queue));}publicObject remove(Object key){processQueue();//throw out garbage collected values firstreturnhash.remove(key);}publicvoidclear(){hardCache.clear();processQueue();//throw out garbage collected valueshash.clear();}publicintsize(){processQueue();//throw out garbage collected values firstreturnhash.size();}publicSet entrySet(){//no, no, you may NOT do that!!! GRRRthrownewUnsupportedOperationException();}}
推荐阅读
- 有了这款可视化工具,Java 应用性能调优 so easy
- Java中堆内存和栈内存详解
- Go语言 CPU 性能、内存分析调试方法大汇总:你要的都在这
- Java 10 大装 B 写法,看完可以出去吹了!
- 简单解释7个主要JavaScript概念
- JavaScript之call和apply的模拟实现
- Android 中部分内存泄漏示例及解决方案
- 不借助 Javascript,利用 SVG 快速构建马赛克效果
- JavaScript高手进阶:安全键盘
- 华为|华为手机内存不够怎么破?内存升级还是插NM存储卡
