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


当前回答

WeakReference:只弱引用的对象将在每个GC周期(minor或full)收集。

SoftReference:当只被软引用的对象被收集时,取决于:

-XX:SoftRefLRUPolicyMSPerMB=N标志(默认值是1000,也就是1秒) 堆中的空闲内存量。 例子: 堆有10MB的空闲空间(在完全GC之后); - xx: SoftRefLRUPolicyMSPerMB = 1000 如果只被SoftReference引用的对象上次被访问的时间大于10秒,则该对象将被收集。

其他回答

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

这篇文章对于理解强引用、软引用、弱引用和幻影引用非常有帮助。


总结一下,

如果对一个对象只有弱引用(没有强引用),那么该对象将在下一个GC循环中被GC回收。

如果对对象只有软引用(没有强引用),那么只有当JVM内存耗尽时,GC才会回收该对象。


所以你可以说,强引用具有强大的功能(GC永远不会收集)。

软引用比弱引用更强大(因为它们可以逃避GC循环,直到JVM耗尽内存)

弱引用甚至不如软引用强大(因为它们不能逃避任何GC循环,如果对象没有其他强引用,就会被回收)。


餐厅的类比

服务员- GC 堆中的对象 餐厅区域/空间-堆空间 新客户-在餐厅想要桌子的新对象

现在,如果您是一个强客户(类似于强引用),那么即使餐厅里来了一个新客户或发生了其他事情,您也不会离开您的表(堆上的内存区域)。服务员没有权利告诉你(甚至要求你)离开餐厅。

如果你是一个软顾客(类似于软参考),那么如果餐厅来了一个新顾客,服务员不会让你离开桌子,除非没有其他空桌子来容纳新顾客。(换句话说,只有当一个新顾客进来,并且没有其他的桌子给这个新顾客时,服务员才会叫你离开桌子)

如果你是一个弱顾客(类似于弱参考),那么服务员可以根据他的意愿(在任何时候)要求你离开餐厅:P

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),使用弱引用。

为了给出一个动态内存使用方面,我做了一个实验,在重物的重负载下,将强、软、弱和幻影引用保留到程序结束。然后监控堆使用和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.