Java中的SoftReference和WeakReference有什么区别?
阅读原文时间:2021年04月20日阅读:1

本文翻译自:What's the difference between SoftReference and WeakReference in Java?

java.lang.ref.WeakReferencejava.lang.ref.SoftReference之间有什么区别?


#1楼

参考:https://stackoom.com/question/1FxD/Java中的SoftReference和WeakReference有什么区别


#2楼

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

Principle: weak reference is related to garbage collection. *原理: weak reference与垃圾收集有关。* Normally, object having one or more reference will not be eligible for garbage collection. 通常,具有一个或多个reference对象将不符合垃圾回收的条件。
The above principle is not applicable when it is weak reference . weak reference时,上述原则不适用。 If an object has only weak reference with other objects, then its ready for garbage collection. 如果一个对象只有弱引用其他对象,那么它就可以进行垃圾回收了。

Let's look at the below example: We have an Map with Objects where Key is reference a object. 让我们看看下面的例子:我们有一个带有对象的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());

    }
}

Now, during the execution of the program we have made emp = null . 现在,在执行程序期间,我们使emp = null The Map holding the key makes no sense here as it is null . 持有密钥的Map在这里没有任何意义,因为它是null In the above situation, the object is not garbage collected. 在上述情况下,对象不是垃圾回收。

WeakHashMap WeakHashMap中

WeakHashMap is one where the entries ( key-to-value mappings ) will be removed when it is no longer possible to retrieve them from the Map . WeakHashMap是在不再可能从Map检索条目时将删除条目( key-to-value mappings )的地方。

Let me show the above example same with WeakHashMap 让我用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());
    }
}

Output: Took 20 calls to System.gc() to result in aMap size of : 0. *输出: 20 calls to System.gc()进行20 calls to System.gc()得到的aMap size为:0。*

WeakHashMap has only weak references to the keys, not strong references like other Map classes. WeakHashMap只有对键的弱引用,而不像其他Map类那样强引用。 There are situations which you have to take care when the value or key is strongly referenced though you have used WeakHashMap . 虽然您已经使用了WeakHashMap但在强烈引用值或键时,您必须注意这些情况。 This can avoided by wrapping the object in a WeakReference . 通过将对象包装在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 References. 软参考。

Soft Reference is slightly stronger that weak reference. Soft Reference比弱参考略强。 Soft reference allows for garbage collection, but begs the garbage collector to clear it only if there is no other option. 软引用允许垃圾收集,但只有在没有其他选项时才请求垃圾收集器清除它。

The garbage collector does not aggressively collect softly reachable objects the way it does with weakly reachable ones -- instead it only collects softly reachable objects if it really "needs" the memory. 垃圾收集器不会像弱可达对象一样积极地收集可轻松访问的对象 - 而是只收集可轻松访问的对象(如果它真的“需要”内存)。 Soft references are a way of saying to the garbage collector, "As long as memory isn't too tight, I'd like to keep this object around. But if memory gets really tight, go ahead and collect it and I'll deal with that." 软引用是对垃圾收集器说的一种方式,“只要内存不是太紧,我就想保留这个对象。但是如果内存变得非常紧张,请继续收集它,我将处理接着就,随即。” The garbage collector is required to clear all soft references before it can throw OutOfMemoryError . 垃圾收集器需要清除所有软引用,然后才能抛出OutOfMemoryError


#3楼

Weak references are collected eagerly. 急切地收集弱引用。 If GC finds that an object is weakly reachable (reachable only through weak references), it'll clear the weak references to that object immediately. 如果GC发现某个对象是弱可达的(只能通过弱引用访问),它将立即清除对该对象的弱引用。 As such, they're good for keeping a reference to an object for which your program also keeps (strongly referenced) "associated information" somewere, like cached reflection information about a class, or a wrapper for an object, etc. Anything that makes no sense to keep after the object it is associated with is GC-ed. 因此,它们很适合保存对程序也保留(强烈引用)“关联信息”的对象的引用,例如关于类的缓存反射信息,或对象的包装器等。任何使得在它与之关联的对象之后保持不变是GC-ed。 When the weak reference gets cleared, it gets enqueued in a reference queue that your code polls somewhere, and it discards the associated objects as well. 当弱引用被清除时,它会在代码轮询某个地方的引用队列中排队,并且它也会丢弃关联的对象。 That is, you keep extra information about an object, but that information is not needed once the object it refers to goes away. 也就是说,您保留有关对象的额外信息,但一旦它引用的对象消失,就不需要该信息。 Actually, in certain situations you can even subclass WeakReference and keep the associated extra information about the object in the fields of the WeakReference subclass. 实际上,在某些情况下,您甚至可以继承WeakReference,并在WeakReference子类的字段中保留有关该对象的相关额外信息。 Another typical use of WeakReference is in conjunction with Maps for keeping canonical instances. WeakReference的另一个典型用法是与Maps一起保存规范实例。

SoftReferences on the other hand are good for caching external, recreatable resources as the GC typically delays clearing them. 另一方面,SoftReferences适用于缓存外部可再生资源,因为GC通常会延迟清除它们。 It is guaranteed though that all SoftReferences will get cleared before OutOfMemoryError is thrown, so they theoretically can't cause an OOME[*]. 虽然在抛出OutOfMemoryError之前所有SoftReferences都会被清除,但是理论上它们不会导致OOME [*]。

Typical use case example is keeping a parsed form of a contents from a file. 典型的用例示例是从文件中保留已解析形式的内容。 You'd implement a system where you'd load a file, parse it, and keep a SoftReference to the root object of the parsed representation. 您将实现一个系统,您可以在其中加载文件,解析文件,并将SoftReference保留到已解析表示的根对象。 Next time you need the file, you'll try to retrieve it through the SoftReference. 下次需要该文件时,您将尝试通过SoftReference检索它。 If you can retrieve it, you spared yourself another load/parse, and if the GC cleared it in the meantime, you reload it. 如果你可以检索它,你可以省去另一个加载/解析,如果GC在此期间清除它,你重新加载它。 That way, you utilize free memory for performance optimization, but don't risk an OOME. 这样,您可以利用可用内存进行性能优化,但不要冒OOME风险。

Now for the [*]. 现在为[*]。 Keeping a SoftReference can't cause an OOME in itself. 保持SoftReference本身不会导致OOME。 If on the other hand you mistakenly use SoftReference for a task a WeakReference is meant to be used (namely, you keep information associated with an Object somehow strongly referenced, and discard it when the Reference object gets cleared), you can run into OOME as your code that polls the ReferenceQueue and discards the associated objects might happen to not run in a timely fashion. 另一方面,如果您错误地将SoftReference用于任务,则应使用WeakReference(即,您以某种方式强烈引用与Object关联的信息,并在Reference对象被清除时丢弃它),您可以运行到OOME中您的代码轮询ReferenceQueue并丢弃关联的对象可能不会及时运行。

So, the decision depends on usage - if you're caching information that is expensive to construct, but nonetheless reconstructible from other data, use soft references - if you're keeping a reference to a canonical instance of some data, or you want to have a reference to an object without "owning" it (thus preventing it from being GC'd), use a weak reference. 因此,决定取决于使用情况 - 如果您正在缓存构建成本高昂的信息,但仍然可以从其他数据重建,请使用软引用 - 如果您要保留对某些数据的规范实例的引用,或者您希望在没有“拥有”它的情况下引用一个对象(从而防止它被GC化),使用弱引用。


#4楼

SoftReference is designed for caches. SoftReference专为缓存而设计。 When it is found that a WeakReference references an otherwise unreachable object, then it will get cleared immediately. 当发现WeakReference引用其他无法访问的对象时,它将立即被清除。 SoftReference may be left as is. SoftReference可以保留原样。 Typically there is some algorithm relating to the amount of free memory and the time last used to determine whether it should be cleared. 通常,存在一些与空闲存储量和最后用于确定是否应该被清除的时间有关的算法。 The current Sun algorithm is to clear the reference if it has not been used in as many seconds as there are megabytes of memory free on the Java heap (configurable, server HotSpot checks against maximum possible heap as set by -Xmx ). 当前的Sun算法是清除引用,如果它没有在Java堆上有多兆字节可用内存的时间内使用(可配置,服务器HotSpot检查-Xmx设置的最大可能堆)。 SoftReference s will be cleared before OutOfMemoryError is thrown, unless otherwise reachable. OutOfMemoryError之前,将清除SoftReference ,除非另有可访问。


#5楼

From Understanding Weak References , by Ethan Nicholas: 来自理解弱参考 ,由Ethan Nicholas撰写:

Weak references 弱参考

A _weak reference , simply put, is a reference that isn't strong enough to force an object to remain in memory._ 简单地说, 弱引用是一个不足以强迫对象保留在内存中的引用。 Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself. 弱引用允许您利用垃圾收集器为您确定可达性的能力,因此您不必自己执行此操作。 You create a weak reference like this: 你创建一个像这样的弱引用:

WeakReference weakWidget = new WeakReference(widget);

and then elsewhere in the code you can use weakWidget.get() to get the actual Widget object. 然后在代码中的其他地方你可以使用weakWidget.get()来获取实际的Widget对象。 Of course the weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the widget) that weakWidget.get() suddenly starts returning null . 当然,弱引用不足以阻止垃圾收集,因此您可能会发现(如果没有对小部件的强引用) weakWidget.get()突然开始返回null

Soft references 软参考

A _soft reference is exactly like a weak reference, except that it is less eager to throw away the object to which it refers._ 软引用与弱引用完全相同,只是它不太愿意丢弃它引用的对象。 An object which is only weakly reachable (the strongest references to it are WeakReferences ) will be discarded at the next garbage collection cycle, but an object which is softly reachable will generally stick around for a while. 一个只能弱到达的对象(对它的最强引用是WeakReferences )将在下一个垃圾收集周期被丢弃,但是一个可以轻松到达的对象通常会暂停一段时间。

SoftReferences aren't _required to behave any differently than WeakReferences , but in practice softly reachable objects are generally retained as long as memory is in plentiful supply._ SoftReferences 不需要WeakReferences任何不同的行为,但实际上,只要内存供应充足,就可以保留软可访问对象。 This makes them an excellent foundation for a cache, such as the image cache described above, since you can let the garbage collector worry about both how reachable the objects are (a strongly reachable object will _never be removed from the cache) and how badly it needs the memory they are consuming._ 这使得它们成为缓存的良好基础,例如上面描述的图像缓存,因为您可以让垃圾收集器担心对象的可达性( 永远不会从缓存中移除强可达对象)以及它有多糟糕需要他们消耗的记忆。

And Peter Kessler added in a comment: Peter Kessler在评论中补充道:

The Sun JRE does treat SoftReferences differently from WeakReferences. Sun JRE确实以不同于WeakReferences的方式处理SoftReferences。 We attempt to hold on to object referenced by a SoftReference if there isn't pressure on the available memory. 如果可用内存没有压力,我们会尝试保持SoftReference引用的对象。 One detail: the policy for the "-client" and "-server" JRE's are different: the -client JRE tries to keep your footprint small by preferring to clear SoftReferences rather than expand the heap, whereas the -server JRE tries to keep your performance high by preferring to expand the heap (if possible) rather than clear SoftReferences. 一个细节:“-client”和“-server”JRE的策略是不同的:-client JRE尝试通过清除SoftReferences而不是扩展堆来保持您的足迹小,而-server JRE尝试保留您的通过优先扩展堆(如果可能)而不是清除SoftReferences来提高性能。 One size does not fit all. 一种尺寸并不适合所有人。


#6楼

In Java ; *在Java中 ;* order from strongest to weakest, there are: Strong, Soft, Weak and Phantom 从最强到最弱的顺序,有:强,软,弱和幻影

A Strong reference is a normal reference that protects the referred object from collection by GC. *强引用是一种常规引用,用于保护引用的对象不受GC的收集。* ie Never garbage collects. 即从不垃圾收集。

A Soft reference is eligible for collection by garbage collector, but probably won't be collected until its memory is needed. *Soft引用有资格由垃圾收集器收集,但在需要内存之前可能不会收集。* ie garbage collects before OutOfMemoryError . 即垃圾在OutOfMemoryError之前收集。

A Weak reference is a reference that does not protect a referenced object from collection by GC. *弱引用是不保护引用对象不受GC收集的引用。* ie garbage collects when no Strong or Soft refs. 即垃圾收集时没有强或软的参考。

A Phantom reference is a reference to an object is phantomly referenced after it has been finalized, but before its allocated memory has been reclaimed. *幻像引用是对一个对象的引用,它在完成后被引用,但在其已分配的内存被回收之前被引用。*

Source 资源

Analogy: Assume a JVM is a kingdom, Object is a king of the kingdom, and GC is an attacker of the kingdom who tries to kill the king(object). *打个比方:假设一个JVM是一个王国,对象是王国的王者,而GC则是试图杀死国王(对象)的王国的攻击者。*

  • When King is Strong , GC can not kill him. **当King *强者时* ,GC无法杀死他。**
  • When King is Soft , GC attacks him but King rule the kingdom with protection until resource are available. 当金是软的时候** ,GC会攻击他,但是King会保护王国,直到有资源可用。**
  • When King is Weak , GC attacks him but rule the kingdom without protection. 当金是弱者时** ,GC会攻击他,但在没有保护的情况下统治王国。**
  • When king is Phantom , GC already killed him but king is available via his soul. 当国王是幻影时** ,GC已经杀死了他,但国王可以通过他的灵魂获得。**