Answers:
从Ethan Nicholas的《理解弱引用》中:
参考不足
一个弱引用,简单地说,是不是强大到足以迫使对象保留在内存中的参考。弱引用使您可以利用垃圾收集器的能力来确定您的可达性,因此您不必自己做。您创建像这样的弱引用:
WeakReference weakWidget = new WeakReference(widget);
然后可以在代码中的其他地方使用
weakWidget.get()
以获得实际Widget
对象。当然,弱引用不足以阻止垃圾回收,因此您可能会发现(如果没有对小部件的强引用)weakWidget.get()
突然开始返回null
。...
软参考
甲软参考酷似弱引用,不同之处在于它是更少急于扔掉其所引用的对象。只能弱访问的对象(对其的最强引用是
WeakReferences
)将在下一个垃圾回收周期中被丢弃,但是柔弱可达性的对象通常会停留一段时间。
SoftReferences
并不需要表现与的任何不同WeakReferences
,但是实际上,只要有足够的内存,通常会保留可软访问的对象。这使它们成为缓存(例如上述图像缓存)的良好基础,因为您可以让垃圾回收器担心对象的可访问性(一个高度可访问的对象将永远不会从缓存中删除)。需要他们正在消耗的内存。
彼得·凯斯勒(Peter Kessler)在评论中添加:
Sun JRE确实将SoftReference与WeakReferences区别对待。如果可用内存没有压力,我们尝试保留由SoftReference引用的对象。一个细节:“-client”和“ -server” JRE的策略不同:-client JRE倾向于通过清除SoftReferences而不是扩展堆来减小占用的空间,而-server JRE尝试保持您的占用空间。通过优先扩展堆(如果可能)而不是清除SoftReferences,可以提高性能。一种尺寸并不适合所有尺寸。
急切地收集弱引用。如果GC发现某个对象是弱可访问的(仅可通过弱引用来访问),它将立即清除对该对象的弱引用。这样,它们对于保留对对象的引用很有用,您的程序也为该对象保留(强烈引用)某些“关联信息”,例如有关类的缓存反射信息或对象的包装等。在与对象关联的对象进行GC编辑后,没有任何保留意义。当弱引用被清除后,它将进入一个队列中,该队列将由您的代码在某个地方轮询,并且也丢弃关联的对象。也就是说,您保留了有关对象的额外信息,但是一旦该对象所指的对象消失了,则不需要该信息。其实,在某些情况下,您甚至可以继承WeakReference的子类,并将有关对象的相关额外信息保留在WeakReference子类的字段中。WeakReference的另一个典型用法是与Maps结合使用,以保留规范实例。
另一方面,SoftReferences非常适合缓存外部可重新创建的资源,因为GC通常会延迟清除它们。尽管可以保证在抛出OutOfMemoryError之前将清除所有SoftReferences,所以从理论上讲它们不会导致OOME [*]。
典型的用例示例是保留文件中内容的解析形式。您将实现一个系统,在该系统中加载文件,解析文件并将SoftReference保留到已解析表示形式的根对象。下次需要该文件时,您将尝试通过SoftReference检索它。如果可以检索它,则可以省去另一次加载/解析,如果GC同时清除了它,则可以重新加载它。这样,您就可以利用空闲内存来优化性能,但是不必冒险使用OOME。
现在为[*]。保持SoftReference本身不会导致OOME。另一方面,如果您错误地将SoftReference用作要使用WeakReference的任务(即,您以某种方式强烈引用了与Object相关的信息,并在清除Reference对象时将其丢弃),则可以在OOME中运行您轮询ReferenceQueue并丢弃关联对象的代码可能无法及时运行。
因此,决定取决于使用情况-如果要缓存构造成本很高但仍然可以从其他数据重构的信息,请使用软引用-如果要保留对某些数据的规范实例的引用,或者要在没有“拥有”对象的情况下拥有对对象的引用(因此可以防止将其进行GC处理),请使用弱引用。
WeakReference
是,在应该使用a的地方,可以容忍在引用超出范围后一小段时间仍然有效的事实,但这不是可取的。
WeakReference
是观察GC运行。参见详细说明:stackoverflow.com/a/46291143/632951
在Java中 ; 从最强到最弱的顺序为:强,弱,弱和幻影
甲强参考是一个正常的参考保护从收集通过GC称为对象。即永不垃圾收集。
一个软引用是符合回收的垃圾收集器,但可能不会被收集到需要它的内存中,直到。即垃圾收集之前OutOfMemoryError
。
一个弱引用是不被GC保护引用的对象从集合的引用。也就是说,当没有强引用或软引用时,垃圾将收集。
一虚引用是它已经敲定后,一个对象的引用phantomly引用,但其分配的内存已经被回收之前。
打个比方:假设JVM是一个王国,对象是该王国的国王,而GC是试图杀死国王(对象)的王国的攻击者。
until memory is available
没有意义。你是说is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use
吗
弱参考 http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
原理: weak reference
与垃圾回收有关。通常,具有一个或多个对象的对象reference
将不符合垃圾回收的条件。
上述原则在适用时不适用weak reference
。如果一个对象仅具有与其他对象的弱引用,则可以对其进行垃圾回收。
让我们看下面的示例:我们有一个Map
with Objects,其中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()
在对结果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
。
NullPointerException
参加aMap.get().put(...)
。
WeakHashMap
示例(因为这是第一个演示弱行为的示例)。看文档的“WeakHashMap中”:"An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. "
使用WeakHashMap中的整个的一点是,你不必申报/传递在WeakReference的; WeakHashMap在内部为您完成此操作。docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
软引用和弱引用之间的唯一真正区别是
垃圾回收器使用算法来决定是否回收可软访问的对象,但始终回收可弱访问的对象。
SoftReference
设计用于缓存。如果发现WeakReference
引用引用了其他无法访问的对象,则它将立即被清除。SoftReference
可能保持原样。通常,有一些算法与空闲内存量以及最后一次确定是否应清除内存的时间有关。当前的Sun算法将清除引用,前提是Java堆上没有可用的内存的秒数内没有使用该引用(可配置的服务器HotSpot将根据设置的最大可能堆进行检查-Xmx
)。除非另外可以达到,否则SoftReference
将在OutOfMemoryError
抛出之前将s清除。
java.lang
。这样的同义词滥用无济于事。
此文章可以超有助于了解强,软,弱,虚引用。
为了给您一个总结,
如果您仅对对象具有弱引用(而没有强引用),则该对象将在下一个GC周期中由GC回收。
如果您仅具有对对象的软引用(没有强引用),则仅当JVM内存不足时,GC才会回收该对象。
所以你可以说,强大的参考具有最终的力量(GC永远无法收集)
软引用功能强大比弱(因为可以逃避GC周期,直到JVM内存不足)
弱引用甚至没有软引用强大(因为它们无法排除任何GC周期,如果对象没有其他强引用,则将其回收)。
餐厅类比
现在,如果您是一个强大的客户(类似于强大的参考客户),那么即使有新客户进来餐厅或发生的事情,您也永远不会离开桌子(堆上的内存区域)。服务员无权告诉您(甚至要求您)离开餐厅。
如果您是软顾客(类似于软顾客),那么如果有新顾客进来,餐厅的服务员将不会要求您离开桌子,除非没有其他空桌子来容纳新顾客。(换句话说,服务员只会在有新客户进场并且没有其他可供该新客户使用的桌子时才要求您离开桌子)
如果您是弱顾客(类似于弱顾客),那么服务员可以(在任何时间)要求您离开餐厅:P
根据文档,必须通过运行中的GC清除松散的WeakReferences 。
根据文档,在抛出OOM之前必须清除松散的SoftReferences 。
那是唯一的真正区别。其他所有内容都不是合同的一部分。(我认为最新文档是合同文件。)
SoftReferences很有用。内存敏感的缓存使用SoftReferences,而不是WeakReferences。
weak_ref.get()
。为时null
,您会了解到在此期间,GC已运行。
至于对WeakReference的错误使用,列表是无止境的:
一个糟糕的hack,实现priority-2软引用,这样您就不必写一个,但是它不能按预期工作,因为即使在有备用内存的情况下,每次 GC运行都会清除缓存。请参阅 https://stackoverflow.com/a/3243242/632951以获取更多信息。(此外,如果您需要两个以上级别的缓存优先级,那该怎么办?您仍然需要一个真正的库。)
将数据与现有类的对象相关联的糟糕方法,但是当您的GC决定在创建弱引用之后决定休息时,它会造成内存泄漏(OutOfMemoryError)。此外,这并不难看:更好的方法是使用元组。
一种糟糕的hack,用于将数据与现有类的对象相关联,其中该类具有使自己无法子类化的神经,并且用在您需要调用的现有功能代码中。在这种情况下,正确的解决方案是编辑类并使它可成为子类,或者编辑函数并使它采用接口而不是类,或者使用替代函数。
equals()
只是对象身份的缓存怎么样?软引用在这里似乎是一种浪费,因为一旦不再牢固地达到关键对象,就不会再有人查找该映射了。
Java中对象可达性状态的六种类型:
有关更多详细信息:https : //www.artima.com/insidejvm/ed2/gc16.html «合拢
为了给出实际的内存使用情况,我对重,重,软,弱和幻像引用进行了实验,这些引用在重负载下将重对象保留到程序结束。然后监视堆使用情况和GC行为。这些指标可能会因情况而异,但可以肯定地提供了高水平的理解。以下是调查结果。
重负载下的堆和GC行为
您可以在此处获得有关该实验的更多深度图,统计数据和观察结果。
WeakReference:在每个GC周期(次要或完全)中,仅收集被弱引用的对象。
SoftReference:何时收集仅被软引用的对象取决于:
-XX:SoftRefLRUPolicyMSPerMB = N标志(默认值为1000,即1秒)
堆中的可用内存量。
例:
如果最后一次访问大于10秒,则仅由SoftReference引用的对象将被收集。