Java中的SoftReference和WeakReference有什么区别?

有什么不同?

从理解弱的参考 ,由伊桑尼古拉斯:

弱引用

简而言之,一个薄弱的参照是一个不足以强迫一个客体留在记忆中的参照。 弱引用允许你利用垃圾收集器的能力来确定你的可达性,所以你不必自己去做。 你创build一个像这样的弱引用:

WeakReference weakWidget = new WeakReference(widget); 

然后在代码的其他地方可以使用weakWidget.get()来获取实际的Widget对象。 当然,弱引用不足以防止垃圾收集,所以你可能会发现(如果没有强的引用的部件) weakWidget.get()突然开始返回null

软参考

一个软引用就像一个弱引用,只是它不那么渴望抛弃它引用的对象。 一个弱可达的对象(最强引用是WeakReferences )将在下一个垃圾收集周期被丢弃,但是一个可以轻松到达的对象通常会持续一段时间。

SoftReferences并不要求WeakReferences行为不同,但实际上,只要内存充足,软性可访问的对象通常会被保留。 这使得它们成为caching(如上面描述的图像caching)的良好基础,因为您可以让垃圾回收器担心对象的可访问性( 永远不会从caching中删除强可及的对象),以及它有多糟糕需要他们消耗的内存。

Peter Kessler在评论中补充道:

Sun JRE不同于WeakReferences对待SoftReference。 如果可用内存没有压力,我们试图保留由SoftReference引用的对象。 一个细节:“客户端”和“服务器”JRE的策略是不同的:客户端JRE通过优先清除SoftReference而不是扩展堆来保持足迹的小型化,而服务器JRE则试图保持性能高,喜欢扩大堆(如果可能),而不是清除SoftReferences。 一个尺寸不适合所有。

弱引用是热切收集的。 如果GC发现一个对象是弱可达的(只能通过弱引用才能访问),它将立即清除对该对象的弱引用。 因此,它们对于保持一个对象的引用是很有用的,因为这个对象对于某个对象而言,也可以保存(强引用)“关联信息”,比如关于类的cachingreflection信息,或者对象的包装等等。在与其相关联的对象之后没有意义保留GC-ed。 当弱引用被清除时,它将被放入引用队列中,代码在某处进行轮询,同时也丢弃关联的对象。 也就是说,你保留关于一个对象的额外信息,但是一旦它引用的对象消失,这个信息就不需要了。 实际上,在某些情况下,您甚至可以inheritanceWeakReference的子类并在WeakReference子类的字段中保留关于该对象的相关额外信息。 WeakReference的另一个典型用途是与Maps保持规范化的实例。

另一方面,SoftReference适用于caching外部可重新调用的资源,因为GC通常会延迟清除它们。 尽pipe在引发OutOfMemoryError之前,所有的SoftReference都会被清除,所以理论上它们不会导致OOME [*]。

典型的用例是从文件中保存内容的parsingforms。 你会实现一个系统,你可以加载一个文件,parsing它,并且保留一个SoftReference到parsing表示的根对象。 下一次你需要这个文件,你会试着通过SoftReference来获取它。 如果你可以检索它,你可以省去另外一个加载/parsing,如果GC在这段时间内清除了它,你可以重新加载它。 这样,您可以利用空闲内存来优化性能,但不要冒险OOME。

现在为[*]。 保持SoftReference本身不会导致OOME。 另一方面,如果您错误地将SoftReference用于某项任务,则应使用WeakReference(即,您保留与Object以某种方式强引用相关联的信息,并且在Reference对象被清除时将其丢弃),则可以作为OOME运行您的代码轮询ReferenceQueue并放弃关联的对象可能不会及时运行。

所以,这个决定取决于使用情况 – 如果你caching的信息构build起来很昂贵,但是可以从其他数据中重build,那么使用软引用 – 如果你保留对某些数据的规范实例的引用,或者你想在没有“拥有”的情况下引用一个对象(从而阻止它成为GC'd),使用一个弱引用。

在Java中 ; 从最强到最弱,有:强,软,弱和幻影

一个强有力的参考是一个正常的参考,保护引用的对象从GC收集。 即从不垃圾收集。

软引用有资格被垃圾收集器收集,但可能不会收集,直到需要它的内存。 即垃圾收集之前OutOfMemoryError

弱引用是一个引用,它不保护引用的对象不被GC收集。 即垃圾收集没有强或软的裁判。

Phantom引用是一个对象的引用,它在被完成之后,但是在分配的内存被回收之前被幻影引用。

资源

比喻:假设一个JVM是一个王国,物体是王国之王,GC是试图杀死国王(物体)的王国的攻击者。

  • 当国王强大的时候 ,GC不能杀死他。
  • 当国王是软的 ,GC攻击他,但国王统治王国,直到资源可用。
  • 当国王衰弱的时候 ,GC攻击他,却没有保护地统治这个王国。
  • 当国王是幽灵时 ,GC已经杀死了他,但是国王可以通过他的灵魂获得。

弱参考 http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html

原理: weak reference与垃圾收集有关。 通常,具有一个或多个reference对象将不符合垃圾回收的条件。
上述原则是weak reference时不适用的。 如果一个对象只有其他对象的弱引用,那么它就可以进行垃圾收集了。

让我们看看下面的例子:我们有一个Map对象,其中Key引用一个对象。

 import java.util.HashMap; public class Test { public static void main(String args[]) { HashMap<Employee, EmployeeVal> aMap = new HashMap<Employee, EmployeeVal>(); Employee emp = new Employee("Vinoth"); EmployeeVal val = new EmployeeVal("Programmer"); aMap.put(emp, val); emp = null; System.gc(); System.out.println("Size of Map" + aMap.size()); } } 

现在,在程序的执行过程中,我们使emp = null 。 持有钥匙的Map在这里没有意义,因为它是null 。 在上述情况下,对象不是垃圾收集。

WeakHashMap中

WeakHashMap是当条目( key-to-value mappings )不再可能从Map检索时被删除的地方。

让我用WeakHashMap显示上面的例子

 import java.util.WeakHashMap; public class Test { public static void main(String args[]) { WeakHashMap<Employee, EmployeeVal> aMap = new WeakHashMap<Employee, EmployeeVal>(); Employee emp = new Employee("Vinoth"); EmployeeVal val = new EmployeeVal("Programmer"); aMap.put(emp, val); emp = null; System.gc(); int count = 0; while (0 != aMap.size()) { ++count; System.gc(); } System.out.println("Took " + count + " calls to System.gc() to result in weakHashMap size of : " + aMap.size()); } } 

输出: 20 calls to System.gc()进行了20 calls to System.gc()导致aMap size为:0。

WeakHashMap只有弱键引用,不像其他Map类那样强引用。 有些情况下,当你使用WeakHashMap时,值或键被强引用时,你必须小心。 这可以通过将对象封装在WeakReference中来避免。

 import java.lang.ref.WeakReference; import java.util.HashMap; public class Test { public static void main(String args[]) { HashMap<Employee, EmployeeVal> map = new HashMap<Employee, EmployeeVal>(); WeakReference<HashMap<Employee, EmployeeVal>> aMap = new WeakReference<HashMap<Employee, EmployeeVal>>( map); map = null; while (null != aMap.get()) { aMap.get().put(new Employee("Vinoth"), new EmployeeVal("Programmer")); System.out.println("Size of aMap " + aMap.get().size()); System.gc(); } System.out.println("Its garbage collected"); } } 

软参考。

Soft Reference略强于弱参考。 软引用允许垃圾收集,但是要求垃圾收集器只在没有其他选项的情况下清除垃圾收集器。

垃圾收集器不会像弱可达的那样积极地收集软性可达的对象,而是只收集软性可达的对象,如果它真的“需要”内存的话。 软引用是对垃圾收集器说的一种方式:“只要内存不太紧,我想保留这个对象,但是如果内存变得非常紧张,那就去收集它吧,我会处理接着就,随即。” 垃圾收集器需要清除所有软引用,才能抛出OutOfMemoryError

软引用和弱引用之间唯一真正的区别是垃圾回收器uses algorithms to decide whether or not to reclaim a softly reachable object, but always reclaims a weakly reachable object.

SoftReference是专为caching。 当发现WeakReference引用一个不可达的对象时,它将立即被清除。 SoftReference可以保持原样。 通常存在一些与可用内存量和上次用于确定是否应该清除的时间有关的algorithm。 目前的Sunalgorithm是清除引用,如果没有在Java堆上有几MB的可用内存(可configuration,服务器HotSpot根据-Xmx设置的最大可能堆检查)没有使用它的时间。 SoftReference将在OutOfMemoryError抛出之前被清除,除非可以被其他方式访问。

Java中的六种types的对象可达性状态 –

  1. 强烈的可达对象 – GC 不会收集( 回收这类对象所占用的内存 )。 这些可以通过根节点或其他可以到达的对象 (即通过局部variables,类variables,实例variables等)
  2. 到达的对象 – GC 可能会根据内存争用尝试收集这类对象。 这些可以通过一个或多个软参考对象从根部到达
  3. 可达的物体 – GC 必须收集这种物体。 这些可以通过一个或多个弱引用对象从根部访问
  4. 可复原的对象 – GC已经在收集这些对象的过程中。 但是他们可能会回到其中一个州 – 强/弱/弱由执行一些终结者
  5. 幽灵般可到达的对象 – GC 已经在收集这些对象的过程中,并且已经确定不能被任何终结器复活(如果它本身声明了finalize()方法,那么它的终结器已经被运行) 。 这些通过一个或多个幻影参考对象从根部到达
  6. 无法到达的对象 – 一个对象既不强,柔和,弱,也不是幻像可达,不可重新调整。 这些对象准备好回收

欲了解更多详情: https : //www.artima.com/insidejvm/ed2/gc16.html «崩溃

唯一真正的区别

根据文档 ,松散的WeakReferences 必须由正在运行的GC清除。

根据文档 ,在引发OOM之前必须清除松散的SoftReferences。

这是唯一的真正的区别。 其他一切都不是合同的一部分。 (我会假设最新的文件是契约性的。)

SoftReferences是有用的。 内存敏感的caching使用SoftReferences,而不是WeakReferences。


WeakReference的唯一正确使用是观察GC运行。 您可以通过创build一个新的WeakReference,其对象立即超出范围,然后尝试从weak_ref.get()获取null。 当它为null ,你知道在这个持续时间之间,GC跑了。

至于WeakReference的不正确使用,列表是无止境的:

  • 一个糟糕的黑客实施优先级2 softreference,这样你不必写一个, 它不能如预期的那样工作,因为caching将在每次 GC运行时被清除,即使有空闲的内存。 有关phails,请参阅https://stackoverflow.com/a/3243242/632951 。 (另外,如果你需要两个以上的caching优先级,你还是需要一个真正的库。

  • 一个糟糕的破解将数据与现有类的对象关联起来, 但是当您的GC在创build弱引用后决定rest时,它会创build一个内存泄漏(OutOfMemoryError)。 此外,它超越丑陋:更好的方法是使用元组。

  • 将数据与现有类的对象关联起来的一种糟糕手段,类中的类可以使其本身不可子类化,并用于您需要调用的现有函数代码中。 在这种情况下,正确的解决scheme是编辑类并使其可以子类化,或者编辑函数并使其接口而不是类,或者使用替代函数。

一个人应该知道,一个弱引用的对象只有在只有弱引用时才会被收集。 如果它有一个强大的参考,它不会被收集,无论它有多less弱的参考。

弱参考

当有一个或多个对象的引用时,它不会被垃圾收集在Java中。 但是这个规则取决于它是什么types的参考。 如果一个对象只有与其他对象相关的弱引用,那么它是垃圾收集的有效候选者。

让我们以一个示例场景来更好地理解它。 让TextView成为一个对象(最近在Android中编程,所以使用它的类,例如:-)),我们将有程序生成的id用于识别。 这些id用于引用TextView的其他对象。

 ... Map textViewIdMap = new HashMap(); textViewIdMap.put(textView1, iD1); textViewIdMap.put(textView2, iD2) ... 

键是TextView对象,值是Id。 现在,在程序的执行过程中,我们删除了一个TextView对象,称为textView1。 我们不需要这个视图对象,所以我们已经把它设为null。 现在,将存储在HashMap中的键值对(textView1,iD1)将会发生什么。 这对现在是没有意义的,它不是必需的,因为textview本身是空的。

所以,编程我们需要确保,当一个textView被删除,然后在地图中的相应条目应该被删除。 只有这样,这个对象才成为垃圾收集的候选对象。 否则,即使它在运行时没有被使用,这个陈旧的对象也不会被垃圾收集。

软参考

软参考略强于弱参考。 软引用允许垃圾收集,但是要求垃圾收集器只在没有其他选项的情况下清除垃圾收集器。 也就是说,它有资格进行垃圾回收,但是垃圾收集器可以根据它所具有的内存紧缩来移除它。 如果剩余的内存很less,而且能够回收内存,则会收集软引用。

WeakReference :每个GC周期(小或全)收集只被弱引用的对象。

SoftReference :当仅仅被软引用的对象被收集取决于:

  1. -XX:SoftRefLRUPolicyMSPerMB = N标志(默认值是1000,也就是1秒)

  2. 堆中的可用内存量。

    例:

    • 堆有10MB的可用空间(全GC之后);
    • -XX:SoftRefLRUPolicyMSPerMB = 1000

    然后,如果最后一次访问的对象被SoftReference引用的对象将被收集超过10秒。