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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/299659/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:48:16  来源:igfitidea点击:

What's the difference between SoftReference and WeakReference in Java?

javareferenceweak-referencessoft-references

提问by driekken

采纳答案by Michael Myers

From Understanding Weak References, by 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 Widgetobject. 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.

...

Soft references

A soft referenceis 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.

SoftReferencesaren't requiredto behave any differently than WeakReferences, but in practice softly reachable objects are generally retained as long as memory is in plentiful supply. 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 neverbe removed from the cache) and how badly it needs the memory they are consuming.

弱引用

一个弱引用,简单地说,是不是强大到足以迫使对象保留在内存中的参考。弱引用允许您利用垃圾收集器的能力来确定您的可达性,因此您不必自己做。你创建一个弱引用是这样的:

WeakReference weakWidget = new WeakReference(widget);

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

...

软引用

软参考酷似弱引用,不同之处在于它是更少急于扔掉其所引用的对象。一个只有弱可达的对象(对它的最强引用是WeakReferences)将在下一个垃圾收集周期被丢弃,但一个软可达的对象通常会停留一段时间。

SoftReferences并不需要向任何行为不同于 WeakReferences,但在实践中轻轻地可达对象一般保留,只要内存供应充足。这使它们成为缓存的绝佳基础,例如上述图像缓存,因为您可以让垃圾收集器担心对象的可达性(强可达对象永远不会从缓存中删除)以及它的严重程度需要他们消耗的内存。

And Peter Kessler added in a comment:

彼得凯斯勒在评论中补充道:

The Sun JRE does treat SoftReferences differently from WeakReferences. We attempt to hold on to object referenced by a SoftReference if there isn't pressure on the available memory. 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. One size does not fit all.

Sun JRE 确实将 SoftReferences 与 WeakReferences 区别对待。如果可用内存没有压力,我们会尝试保留由 SoftReference 引用的对象。一个细节:“-client”和“-server”JRE 的策略是不同的:-client JRE 试图通过更喜欢清除 SoftReferences 而不是扩展堆来保持你的足迹较小,而 -server JRE 试图保持你的通过更喜欢扩展堆(如果可能)而不是清除 SoftReferences 来提高性能。一种尺寸并不适合所有人。

回答by driekken

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. 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. 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. Another typical use of WeakReference is in conjunction with Maps for keeping canonical instances.

弱引用被急切地收集。如果 GC 发现一个对象是弱可达的(只能通过弱引用可达),它会立即清除对该对象的弱引用。因此,它们非常适合保留对您的程序还保留(强引用)“关联信息”的对象的引用,例如有关类的缓存反射信息或对象的包装器等。任何使在与它相关联的对象被 GC 处理后保留是没有意义的。当弱引用被清除时,它会被排入您的代码在某处轮询的引用队列中,并且它也会丢弃关联的对象。也就是说,您保留有关对象的额外信息,但是一旦它所引用的对象消失,就不需要该信息。实际上,在某些情况下,您甚至可以将 WeakReference 子类化,并在 WeakReference 子类的字段中保留有关对象的相关额外信息。WeakReference 的另一个典型用途是与 Maps 结合使用以保持规范实例。

SoftReferences on the other hand are good for caching external, recreatable resources as the GC typically delays clearing them. It is guaranteed though that all SoftReferences will get cleared before OutOfMemoryError is thrown, so they theoretically can't cause an OOME[*].

另一方面,SoftReferences 有利于缓存外部的、可重新创建的资源,因为 GC 通常会延迟清除它们。尽管可以保证在抛出 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. Next time you need the file, you'll try to retrieve it through the SoftReference. If you can retrieve it, you spared yourself another load/parse, and if the GC cleared it in the meantime, you reload it. That way, you utilize free memory for performance optimization, but don't risk an OOME.

典型的用例示例是保留文件中内容的解析形式。您将实现一个系统,您将在其中加载文件、解析它,并将 SoftReference 保留到已解析表示的根对象。下次您需要该文件时,您将尝试通过 SoftReference 检索它。如果您可以检索它,您就可以避免再次加载/解析,如果 GC 在此期间清除了它,您就重新加载它。这样,您可以利用空闲内存进行性能优化,但不会冒 OOME 风险。

Now for the [*]. Keeping a SoftReference can't cause an OOME in itself. 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 本身不会导致 OOME。另一方面,如果您错误地将 SoftReference 用于要使用 Wea​​kReference 的任务(即,您以某种方式保持与对象关联的信息以某种方式强引用,并在引用对象被清除时丢弃它),您可能会遇到 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.

因此,该决定取决于使用情况 - 如果您正在缓存构建成本高的信息,但仍然可以从其他数据中重建,请使用软引用 - 如果您保留对某些数据的规范实例的引用,或者您想要有一个对象的引用而不“拥有”它(从而防止它被垃圾回收),使用弱引用。

回答by Tom Hawtin - tackline

SoftReferenceis designed for caches. When it is found that a WeakReferencereferences an otherwise unreachable object, then it will get cleared immediately. SoftReferencemay be left as is. 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). SoftReferences will be cleared before OutOfMemoryErroris thrown, unless otherwise reachable.

SoftReference专为缓存而设计。当发现 aWeakReference引用了一个否则无法访问的对象时,它将立即被清除。SoftReference可以保持原样。通常有一些与可用内存量和上次使用的时间相关的算法来确定是否应该清除它。当前的 Sun 算法是,如果在 Java 堆上有 MB 可用内存(可配置,服务器 HotSpot 根据 设置的最大可能堆进行检查)的秒数内没有使用该引用,则清除该引用-XmxSoftReferences 将在OutOfMemoryError抛出之前被清除,除非以其他方式可达。

回答by Samir Mangroliya

The only real difference between a soft reference and a weak reference is that

软引用和弱引用之间唯一真正的区别是

the garbage collector uses algorithms to decide whether or not to reclaim a softly reachable object, but always reclaims a weakly reachable object.

垃圾收集器使用算法来决定是否回收一个软可达的对象,但总是回收一个弱可达的对象。

回答by Thalaivar

Weak Referencehttp://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 referenceis related to garbage collection. Normally, object having one or more referencewill not be eligible for garbage collection.
The above principle is not applicable when it is weak reference. If an object has only weak reference with other objects, then its ready for garbage collection.

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

Let's look at the below example: We have an Mapwith Objects where Key is reference a object.

让我们看看下面的例子:我们有一个Mapwith 对象,其中 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. The Mapholding the key makes no sense here as it is null. In the above situation, the object is not garbage collected.

现在,在我们制作的程序执行过程中emp = null。在Map保持关键是没有意义在这里,因为它是null。在上述情况下,对象不会被垃圾回收。

WeakHashMap

弱哈希映射

WeakHashMapis one where the entries (key-to-value mappings) will be removed when it is no longer possible to retrieve them from the Map.

WeakHashMapkey-to-value mappings当不再可能从Map.

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 sizeof : 0.

输出:20 calls to System.gc()结果aMap size为:0。

WeakHashMaphas only weak references to the keys, not strong references like other Mapclasses. There are situations which you have to take care when the value or key is strongly referenced though you have used WeakHashMap. This can avoided by wrapping the object in a WeakReference.

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 References.

软引用。

Soft Referenceis slightly stronger that weak reference. Soft reference allows for garbage collection, but begs the garbage collector to clear it only if there is no other option.

Soft Reference弱参考略强。软引用允许垃圾收集,但只有在没有其他选择时才会请求垃圾收集器清除它。

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

回答by Premraj

In Java; order from strongest to weakest, there are: Strong, Soft, Weak and Phantom

在 Java 中;从强到弱依次为:强、软、弱、幻

A Strong referenceis a normal reference that protects the referred object from collection by GC. i.e. Never garbage collects.

强参考是一个正常的参考保护从收集通过GC称为对象。即从不垃圾收集。

A Soft referenceis eligible for collection by garbage collector, but probably won't be collected until its memory is needed. i.e. garbage collects before OutOfMemoryError.

一个软引用是符合回收的垃圾收集器,但可能不会被收集到需要它的内存中,直到。即垃圾收集之前OutOfMemoryError

A Weak referenceis a reference that does not protect a referenced object from collection by GC. i.e. garbage collects when no Strong or Soft refs.

一个弱引用是不被GC保护引用的对象从集合的引用。即当没有强引用或软引用时垃圾收集。

A Phantom referenceis a reference to an object is phantomly referenced after it has been finalized, but before its allocated memory has been reclaimed.

虚引用是它已经敲定后,一个对象的引用phantomly引用,但其分配的内存已经被回收之前。

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是一个王国,Object是王国的王者,GC是王国的攻击者,试图杀死国王(对象)。

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

回答by V.Vidyasagar

The six types of object reachability states in Java:

Java 中的六种类型的对象可达性状态:

  1. Strongly reachable objects - GC will notcollect (reclaim the memory occupied by) this kind of object. These are reachable via a root node or another strongly reachable object(i.e. via local variables, class variables, instance variables, etc.)
  2. Softly reachable objects - GC may attemptto collect this kind of object depending on memory contention. These are reachable from the root via one or more soft reference objects
  3. Weakly reachable objects - GC mustcollect this kind of object. These are reachable from the root via one or more weak reference objects
  4. Resurrect-ableobjects - GC is already in the process of collecting these objects. But they may go back to one of the states - Strong/Soft/Weakby the execution of some finalizer
  5. Phantomly reachable object - GC is already in the process of collecting these objects and has determined to not be resurrect-able by any finalizer (if it declares a finalize() method itself, then its finalizer will have been run). These are reachable from the root via one or more phantom reference objects
  6. Unreachableobject - An object is neither strongly, softly, weakly, nor phantom reachable, and is not resurrectable. These objects are ready for reclamation
  1. 可达对象 - GC不会收集(回收被占用的内存)这种对象。这些可以通过根节点或另一个强可达对象(即通过局部变量、类变量、实例变量等)访问
  2. 可访问对象 - GC可能会尝试根据内存争用收集此类对象。这些可以通过一个或多个软引用对象从根访问
  3. 可达对象 - GC必须收集这种对象。这些可以通过一个或多个弱引用对象从根访问
  4. 可复活的对象 - GC 已经在收集这些对象的过程中。但是它们可能会通过执行某些终结器返回到其中一种状态 - 强/软/弱
  5. 幻影LY可及对象- GC已经在收集这些对象的过程中,已确定不能复活,能够通过任何终结(如果它声明finalize()方法本身,那么它的终结将已运行)。这些可以通过一个或多个幻像引用对象从根访问
  6. Unreachableobject - 一个对象既不是强的,软的,弱的,也不是幻影可达的,并且是不可复活的。这些对象已准备好回收

For more details: https://www.artima.com/insidejvm/ed2/gc16.html? collapse

更多详情:https: //www.artima.com/insidejvm/ed2/gc16.html?坍塌

回答by Fai Lau

One should be aware that a weakly referenced object will only get collected when it has ONLY weak reference(s). If it has so much as one strong reference, it does not get collected no matter how many weak references it has.

应该知道,弱引用对象只有在只有弱引用时才会被收集。如果它只有一个强引用,那么无论它有多少个弱引用都不会被收集。

回答by Pacerier

The Only Real Difference

唯一真正的区别

Per the doc, loose WeakReferences mustbe cleared by a running GC.

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

Per the doc, loose SoftReferences mustbe cleared before OOM is thrown.

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

That's the only real difference. Everything else is not part of the contract. (I'll assume the latest docs are contractual.)

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

SoftReferences are useful.Memory-sensitive caches use SoftReferences, not WeakReferences.

软引用很有用。内存敏感缓存使用 SoftReferences,而不是 WeakReferences。



唯一的 proper正确使用 Wea​​kReference 是为了观察 GC 运行。为此,您可以创建一个新的 WeakReference,其对象立即超出范围,然后尝试从weak_ref.get()weak_ref.get(). 当它是 时nullnull,您会了解到在此持续时间之间,GC 运行。

As for incorrectuse of WeakReference, the list is endless:

至于WeakReference 的错误使用,不胜枚举:

  • a lousy hack to implement priority-2 softreference such that you don't have to write one, yetit doesn't work as expected because the cache would be cleared on everyGC run, even when there is spare memory. See https://stackoverflow.com/a/3243242/632951for phails. (Besides, what if you need more than 2 levels of cache priority? You'd still gotta need a real library for it.)

  • a lousy hack to associate data with an object of an existing class, yetit creates a memory leak (OutOfMemoryError) when your GC decides to take a break after your weakreferences are created. Besides, it's beyond ugly: A better approach is to use tuples.

  • a lousy hack to associate data with an object of an existing class, where the class has the nerve to make itself non-subclassable, and is used in an existing function codewhich you need to call. In such a case, the proper solution is to either edit the class and make it subclassable, or edit the function and make it take an interface instead of a class, or use an alternative function.

  • 实现优先级 2 软引用的糟糕方法,这样您就不必编写一个,它无法按预期工作,因为每次GC 运行时都会清除缓存,即使有空闲内存。有关phails,请参阅 https://stackoverflow.com/a/3243242/632951。(此外,如果您需要 2 级以上的缓存优先级怎么办?您仍然需要一个真正的库。)

  • 一个糟糕的黑客攻击,与现有的类的对象相关联的数据,它会创建一个内存泄漏(OutOfMemoryError错误)当你的GC决定创建你在WeakReferences后稍事休息。此外,它非常丑陋:更好的方法是使用元组。

  • 将数据与现有类的对象相关联的糟糕方法,其中该类有神经使自己不可子类化,并在您需要调用的现有函数代码中使用。在这种情况下,正确的解决方案是编辑类并使其可子类化,或者编辑函数并使其采用接口而不是类,或者使用替代函数。

回答by Artem Petrov

WeakReference: objects that are only weakly referenced are collected at every GC cycle (minor or full).

WeakReference:在每个 GC 周期(次要或完整)收集仅弱引用的对象。

SoftReference: when objects that are only softly referenced are collected depends on:

SoftReference:何时收集仅软引用的对象取决于:

  1. -XX:SoftRefLRUPolicyMSPerMB=N flag (default value is 1000, aka 1 second)

  2. Amount of free memory in the heap.

    Example:

    • heap has 10MB of free space (after full GC);
    • -XX:SoftRefLRUPolicyMSPerMB=1000

    Then object which is referenced only by SoftReference will be collected if last time when it was accessed is greater then 10 seconds.

  1. -XX:SoftRefLRUPolicyMSPerMB=N 标志(默认值为 1000,即 1 秒)

  2. 堆中的空闲内存量。

    例子:

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

    如果最后一次访问它的时间大于 10 秒,则仅由 SoftReference 引用的对象将被收集。