java WeakReference SoftReference and PhatomReference

Java 2 平台引入了 java.lang.ref 包,其中包括的类可以让您引用对象,而不将它们留在内存中。这些类还提供了与垃圾收集器(garbage collector)之间有限的交互。

先“由强到弱”(只的是和垃圾回收器的关系)明确几个基本概念:
strong references是那种你通常建立的reference,这个reference就是强可及的。这个不会被自动回收。例如:StringBuffer buffer = new StringBuffer();其中这个buffer就是强引用,之所以称为“强”是取决于它如何处理与Garbage Collector的关系的:它是无论如何都不会被回收的。够强的。强引用在某些时候是有个问题的,下边的一个哈希表实例就是很好的说明。而且还有一个问 题就是在缓冲上,尤其是诸如图片等大的结构上。我们在内存中开辟一块区域放置图片缓冲,那我们就希望有个指针指向那块区域。此时若是使用强引用则回强迫图 片留在内存,当你觉得不需要的时候你需要手动移除,否则就是内存泄漏。

WeakReference则类似于可有可无的东西。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内 存空间足够与否,都会回收它的内存,说白了就是一个没那么strong要求垃圾回收器将一个对象保留在内存中。不过,由于垃圾回收器是一个优先级很低的线 程,因此不一定会很快发现那些只具有弱引用的对象。常说的Unreachable和弱引用指代的是一个意思。这可能还是说不清楚,那么我举个例子:
你有一个类叫做Widget,但是由于某种原因它不能通过继承来添加一项功能。当我们想从这个对象中取出一些信息的时候怎么办呢?假设我们需要监视每个 Widget的serial Number,但是这个Widget却偏偏没有这个属性,而且还不可继承...这时候我们想到了用 HashMaps:serialNumberMap.put(widget, widgetSerialNumber);
这不就截了嘛~表面上看起来是ok的,但是正是Widget这个Strong Reference产生了问题。当我们设定某个Widget的SerialNumber不需要的时候,那么要从这个映射表中除去这个映射对,否则我们就有 了内存泄漏或者是出错(移除了有效的SerialNumber)。这个问题听起来很耳熟,是的,在没有垃圾管理机制的语言中这是个常见问题,在JAVA中 我们不用担心。因为我们有WeakReference。我们使用内置的WeakHashMap类,这个类和哈希表HashMap几乎一样,但就是在键 key的地方使用了WeakReference,若一个WeakHashMap key成为了垃圾,那么它对应的入口就会自动被移除。这就解决了上述问题~

SoftReference则也类似于可有可无的东西。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。 只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。弱引用与软引用的区别在于:具有WeakReference的 对象拥有更短暂的生命周期。或者说SoftReference比WeakReference对回收它所指的对象不敏感。一个WeakReference对 象会在下一轮的垃圾回收中被清理,而SoftReference对象则会保存一段时间。SoftReferences并不会主动要求与 WeakReference有什么不同,但是实际上SoftReference对象一般在内存充裕时一般不会被移除,这就是说对于创建缓冲区它们是不错的 选择。它兼有了StrongReference和WeakReference的好处,既能停留在内存中,又能在内存不足是去处理,这一切都是自动的!


PhantomReference为"虚引用",顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚 引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收,也就是说其get方法任何时间都会返回null。虚引用主要用来跟踪对象被垃圾回收的活 动。其必须和引用队列(ReferenceQueue)联合使用,这是与弱引用和软引用最大的不同。WeakReference是在垃圾回收活动之前将对 象入队的,理论上讲这个对象还可以使用finalize()方法使之重生,但是WeakReference仍然是死掉了。 PhantomReferences对象是在对象从内存中清除出去的时候才入队的。也就是说当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会 在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回 收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。它限制了finalize()方法的使用, 更安全也更高效。

我们看看这个包给我们提供了什么类?

WeakReference 类
WeakReference weakref = new WeakReference(ref);
这样 weakref 就是 ref 指向对象的一个 weak reference。要引用这个 weak reference 指向的对象可以用 get 方法。把对象的 weak reference 放入 Hashtable 或者缓存中,当没有 strong reference 指向他们的时候,对象就可以被垃圾收集器回收了。实际上,有一个 WeakHashMap 就是专门做这个事的。一旦WeakReference使用get方法返回null的时候,它指向的对象已经变成了垃圾,这个weakref对象也没什么用 处了。这就需要有一些清理工作了。而ReferenceQueue类就是做这个的,要是你向ReferenceQueue类传递了一个 WeakReference的构造方法,那么当引用所指的对象成为垃圾时,这个引用的对象就会被自动插入到这个引用队列中。你可以在一定时间间隔内处理这 个队列。

SoftReference 类 
可用来实现智能缓存(java.lang.ref.SoftReference is a relatively new class, used to implement smart caches.)假定你有一个对象引用,指向一个大数组:

Object obj = new char[1000000];
并且如果可能的话,你打算一直保存这个数组,但是如果内存极其短缺的话,你乐于释放这个数组。你可以使用一个
soft reference:
SoftReference ref = new SoftReference(obj);
Obj是这个soft reference的引用。在以后你用以下的方式检测这个引用:
if (ref.get() == null)// (referent has been cleared)
else// (referent has not been cleared)
如果这个引用已经被清除了,那么垃圾回收器会收回它所使用的空间,并且你缓存的对象也已经消失。需要注意的是,如果这个指示物还有对它的别的引用,那么垃 圾回收器将不会清除它。这个方案可以被用来实现各种不同类型的缓存,这些缓存的特点是只要有可能对象就会被一直保存下来,但是如果内存紧张对象就被清除 掉。
注意:软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

e.g.

Java代码 收藏代码
  1. importjava.lang.ref.*;
  2. publicclassReferences{
  3. publicstaticvoidmain(String[]args){
  4. ObjectweakObj,phantomObj;
  5. Referenceref;
  6. WeakReferenceweakRef;
  7. PhantomReferencephantomRef;
  8. ReferenceQueueweakQueue,phantomQueue;
  9. weakObj=newString("WeakReference");
  10. phantomObj=newString("PhantomReference");
  11. weakQueue=newReferenceQueue();
  12. phantomQueue=newReferenceQueue();
  13. weakRef=newWeakReference(weakObj,weakQueue);
  14. phantomRef=newPhantomReference(phantomObj,phantomQueue);
  15. //Printreferentstoprovetheyexist.Phantomreferents
  16. //areinaccessiblesoweshouldseeanullvalue.
  17. System.out.println("WeakReference:"+weakRef.get());
  18. System.out.println("PhantomReference:"+phantomRef.get());
  19. //Clearallstrongreferences
  20. weakObj=null;
  21. phantomObj=null;
  22. //Invokegarbagecollectorinhopesthatreferences
  23. //willbequeued
  24. System.gc();
  25. //Seeifthegarbagecollectorhasqueuedthereferences
  26. System.out.println("WeakQueued:"+weakRef.isEnqueued());
  27. //Trytofinalizethephantomreferencesifnotalready
  28. if(!phantomRef.isEnqueued()){
  29. System.out.println("Requestionfinalization.");
  30. System.runFinalization();
  31. }
  32. System.out.println("PhantomQueued:"+phantomRef.isEnqueued());
  33. //Waituntiltheweakreferenceisonthequeueandremoveit
  34. try{
  35. ref=weakQueue.remove();
  36. //Thereferentshouldbenull
  37. System.out.println("WeakReference:"+ref.get());
  38. //Waituntilthephantomreferenceisonthequeueandremoveit
  39. ref=phantomQueue.remove();
  40. System.out.println("PhantomReference:"+ref.get());
  41. //Wehavetoclearthephantomreferenteventhough
  42. //get()returnsnull
  43. ref.clear();
  44. }catch(InterruptedExceptione){
  45. e.printStackTrace();
  46. return;
  47. }
  48. }
  49. }
来自: http://improving.iteye.com/blog/436311

===============================================================================

weakReference一般用来防止内存泄漏,要保证内存被VM回收

softReference的话,好像多用作来实现cache机制.

WeakReference:

弱引用对象,它们并不禁止其指示对象变得可终结,并被终结,然后被回收。弱引用最常用于实现规范化的映射。

假定垃圾回收器确定在某一时间点上某个对象是弱可到达对象。这时,它将自动清除针对此对象的所有弱引用,以及通过强引用链和软引用,可以从其到达该对象的针对任何其他弱可到达对象的所有弱引用。同时它将声明所有以前的弱可到达对象为可终结的。在同一时间或晚些时候,它将那些已经向引用队列注册的新清除的弱引用加入队列。


///
SoftReference:
软引用对象,在响应内存需要时,由垃圾回收器决定是否清除此对象。软引用对象最常用于实现内存敏感的缓存。这里是指在只用在内存将要耗尽时,jvm执行清理时才会清理掉软应用,因此这种效果适宜用作缓存。

假定垃圾回收器确定在某一时间点某个对象是软可到达对象。这时,它可以选择自动清除针对该对象的所有软引用,以及通过强引用链,从其可以到达该对象的针对任何其他软可到达对象的所有软引用。在同一时间或晚些时候,它会将那些已经向引用队列注册的新清除的软引用加入队列。

软可到达对象的所有软引用都要保证在虚拟机抛出 OutOfMemoryError 之前已经被清除。否则,清除软引用的时间或者清除不同对象的一组此类引用的顺序将不受任何约束。然而,虚拟机实现不鼓励清除最近访问或使用过的软引用。

此类的直接实例可用于实现简单缓存;该类或其派生的子类还可用于更大型的数据结构,以实现更复杂的缓存。只要软引用的指示对象是强可到达对象,即正在实际使用的对象,就不会清除软引用。例如,通过保持最近使用的项的强指示对象,并由垃圾回收器决定是否放弃剩余的项,复杂的缓存可以防止放弃最近使用的项

Java内存管理之软引用(Soft Reference)

软引用(Soft Reference)的主要特点是具有较强的引用功能。只有当内存不够的时候才回收这类内存,因此在内存足够的时候,他们通常不被回收。另外,这些引用对象还能保证在Java 抛出OutOfMemory异常之前,被设置为null。他可以用于实现一些常用资源的缓存,实现Cache的功能,保证最大限度的使用内存而不引起OutOfMemory异常。

下面是软引用的实现代码:

Java代码 收藏代码
  1. importjava.lang.ref.SoftReference;
  2. publicclasssoftReference{
  3. publicstaticvoidmain(String[]args){
  4. Aa=newA();
  5. //使用a
  6. a.test();
  7. //使用完了a,将它设置为soft引用类型,并且释放强引用
  8. SoftReferencesr=newSoftReference(a);
  9. a=null;
  10. //下次使用
  11. if(sr!=null){
  12. a=(A)sr.get();
  13. a.test();
  14. }else{
  15. //GC由于低内存,已释放a,因此需要重新装载
  16. a=newA();
  17. a.test();
  18. a=null;
  19. sr=newSoftReference(a);
  20. }
  21. }
  22. }
  23. classA{
  24. publicvoidtest(){
  25. System.out.println("SoftReferencetest");
  26. }
  27. }

软引用技术的引进使Java应用可以更好的管理内存,稳定系统,防止系统内存溢出,避免系统崩溃。因此在处理一些占用内存大而且声明周期较长,但使用并不频繁的对象时应尽量应用该技术。但事物总带有两面性的,有利也有弊,在某些时候对软引用的使用会降低应用的运行效率与性能,例如:应用软引用的对象的初始化过程较为耗时,或者对象的状态在程序的运行过程中发生了变化,都会给重新创建对象与初始化对象带来不同程度的麻烦,有些时候我们要权衡利弊择时应用。

在android中可以巧妙的运用软引用(SoftRefrence)(来源段落:http://winuxxan.blog.51cto.com/2779763/512180)

有些时候,我们使用Bitmap后没有保留对它的引用,因此就无法调用Recycle函数。这时候巧妙的运用软引用,可以使Bitmap在内存快不足时得到有效的释放。如下例:

Java代码 收藏代码
  1. privateclassMyAdapterextendsBaseAdapter{
  2. privateArrayList<SoftReference<Bitmap>>mBitmapRefs=newArrayList<SoftReference<Bitmap>>();
  3. privateArrayList<Value>mValues;
  4. privateContextmContext;
  5. privateLayoutInflatermInflater;
  6. MyAdapter(Contextcontext,ArrayList<Value>values){
  7. mContext=context;
  8. mValues=values;
  9. mInflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  10. }
  11. publicintgetCount(){
  12. returnmValues.size();
  13. }
  14. publicObjectgetItem(inti){
  15. returnmValues.get(i);
  16. }
  17. publiclonggetItemId(inti){
  18. returni;
  19. }
  20. publicViewgetView(inti,Viewview,ViewGroupviewGroup){
  21. ViewnewView=null;
  22. if(view!=null){
  23. newView=view;
  24. }else{
  25. newView=(View)mInflater.inflate(R.layout.image_view,false);
  26. }
  27. Bitmapbitmap=BitmapFactory.decodeFile(mValues.get(i).fileName);
  28. mBitmapRefs.add(newSoftReference<Bitmap>(bitmap));//此处加入ArrayList
  29. ((ImageView)newView).setImageBitmap(bitmap);
  30. returnnewView;
  31. }
  32. }

综合帖子1、http://topic.csdn.net/t/20060327/23/4644203.html

帖子2http://www.blogjava.net/ajie/archive/2005/12/18/24435.html

========================================================

reachable, the following happens:
A set ref of references is determined. ref contains the following elements:
All weak references pointing to obj.
All weak references pointing to objects from which obj is either strongly or softly reachable.
All references in ref are atomically cleared.
All objects formerly being referenced by ref become eligible for finalization.
At some future point, all references in ref will be enqueued with their corresponding reference queues, if any.
Weak references are useful for mappings that should have their entries removed automatically once they are not referenced any more (from outside). The difference between a SoftReference and a WeakReference is the point of time at which the decision is made to clear and enqueue the reference:
A SoftReference should be cleared and enqueued as late as possible, that is, in case the VM is in danger of running out of memory.
A WeakReference may be cleared and enqueued as soon as is known to be weakly-referenced.

(1)WeakReference
WeakReference实现了一个弱引用,弱引用是三种引用(StrongReference、WeakReference、SoftReference)中的一个。一旦垃圾回收器判定一个对象是是弱获取(对象可获取程度分为五种strongly reachable,softly reachable、weakly reachable、phantomly reachable、unreachable),则下列情况发生:
计算一组引用的ref,ref包括下列元素:
所有指向obj的弱引用
所有指向objects的弱引用,objects是软获取对象或者是强获取对象
在ref中的所有引用被自动删除
所有以前被ref引用的对象都符合终止条件的对象(become eligible for finalization)
在未来的某个时间,所有的在ref中的引用将被放入合适的引用队列中
弱引用对那些映射,这些映射中的实体的引用一旦被不存在这些实体将被自动删除。弱引用和软引用的区别是清空和将加入排队的时间点不同:
一个弱引用应该尽可能晚的被清除和加入队列,那是因为如果内存不足是vm将是危险的
弱引用对象是一旦知道引用的是弱获取对象就会被清除和入队。

A SoftReference should be cleared and enqueued as late as possible, that is, in case the VM is in danger of running out of memory.

一个软引用应该尽可能迟的被清理和入列,因此,在这种情况下虚拟机(VM)就存在内存溢出的风险(危险)。

个人理解:问题在“as late as possible”——始终过迟的清理垃圾,肯定就有内存溢出的风险(危险)。 
------------------------------------
All objects formerly being referenced by ref become eligible for finalization.
所有先前被ref引用的对象都将符合垃圾回收(finalization)的条件。
ref:地址引用,java里就是指被new创建的对象。
除非是使用JNI,所占用的内存将不在ref的范围(Thinking in Java 4th, 120页)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值