java.lang.ref.WeakReference和java.lang.ref.SoftReference有什么区别?


当前回答

摘自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. 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 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. 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. 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.

Peter Kessler补充道:

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.

其他回答

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.

另一方面,softreference对于缓存外部的、可重新创建的资源很有好处 因为GC通常会延迟清除它们。尽管如此,这是有保证的 在抛出OutOfMemoryError之前,sofreferferences将被清除 理论上不会引起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本身不会导致OOME。如果 另一方面,你错误地把软参考用在了一个弱参考的任务上 (也就是说,你以某种方式保存与对象相关的信息 ,并在Reference对象获得时丢弃它 清除),您可以运行OOME作为您的代码轮询referencqueuue 而丢弃关联对象可能会发生不及时运行的情况 时尚。

所以,决定取决于使用情况 -如果你缓存的信息构造起来很昂贵,但是 尽管如此,可从其他数据重构,使用软引用 -如果您保留对某些数据的规范实例的引用,或者 您希望拥有对对象的引用,但不“拥有”它(因此 防止它被GC),使用弱引用。

SoftReference is designed for caches. When it is found that a WeakReference references an otherwise unreachable object, then it will get cleared immediately. SoftReference may 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 OutOfMemoryError is thrown, unless otherwise reachable.

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

为了给出一个动态内存使用方面,我做了一个实验,在重物的重负载下,将强、软、弱和幻影引用保留到程序结束。然后监控堆使用和GC行为。这些指标可能因情况而异,但肯定能提供高层次的理解。以下是调查结果。

重负载下的堆和GC行为

Strong/Hard Reference - As program continued, JVM couldn't collect retained strong referenced object. Eventually ended up in "java.lang.OutOfMemoryError: Java heap space" Soft Reference - As program continued, heap usage kept growing, but OLD gen GC happened hen it was nearing max heap. GC started bit later in time after starting program. Weak Reference - As program started, objects started finalizing & getting collected almost immediately. Mostly objects got collected in young generation garbage collection. Phantom Reference - Similar to weak reference, phantom referenced objects also started getting finalized & garbage collected immediately. There were no old generation GC & all objects were getting collected in young generation garbage collection itself.

你可以在这里获得更多关于这个实验的深度图表、统计数据和观察结果。

唯一真正的区别

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

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

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

软引用很有用。内存敏感的缓存使用软引用,而不是弱引用。 WeakReference的唯一正确用法是观察GC运行。为此,您可以创建一个新的WeakReference,其对象立即超出作用域,然后尝试从weak_ref.get()中获取null。当它为空时,您可以了解到在此期间GC运行了。

关于WeakReference的错误使用,列表是无限的:

a lousy hack to implement priority-2 softreference such that you don't have to write one, yet it doesn't work as expected because the cache would be cleared on every GC run, even when there is spare memory. See https://stackoverflow.com/a/3243242/632951 for 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, yet it 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 code which 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.