关于引用:Java中的软引用和弱引用有什么区别?

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

java.lang.ref.WeakReferencejava.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:

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

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

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发现一个对象弱可到达(仅通过弱引用可到达),它将清除立即弱引用该对象。因此,它们对保留对程序也为其保留的对象的引用(强引用)"关联信息"一些,如缓存的关于类或对象包装器等的反射信息。在与之关联的对象之后保留没有意义的任何内容当弱引用被清除时,它将在您的代码在某个地方轮询的引用队列,它将丢弃关联的对象也一样。也就是说,您保留有关对象,但一旦对象引用该信息,就不需要该信息。走开。实际上,在某些情况下,您甚至可以子类Weakreference并保留与对象相关的额外信息在weakreference子类中。另一个典型的用途是weakreference与保存规范实例的映射结合在一起。

另一方面,软引用有利于缓存外部可重新创建的资源。因为GC通常会延迟清除它们。尽管这一切都是有保证的SoftReferences将在抛出OutOfMemoryError之前被清除,因此它们理论上不会引起OOME[*]。

典型的用例示例是从文件。您将实现一个系统,在该系统中您将加载一个文件,对其进行分析,并保留对解析表示的根对象的软引用。下次您需要这个文件,您将尝试通过SoftReference检索它。如果您可以检索它,您省去了另一个加载/解析,如果GC同时清除它,重新加载它。这样,你就可以免费使用内存用于性能优化,但不要冒险使用OOME。

现在为[*]。保持一个软引用本身不能引起OOME。如果另一方面,您错误地将软引用用于任务,weakreference是指要使用(即,您以某种方式保留与对象相关联的信息强引用,并在引用对象清除),您可以将OOME作为轮询引用队列的代码运行。丢弃关联的对象可能会在时尚。

因此,决定取决于使用情况-如果您正在缓存构建成本很高的信息,但是尽管如此,还是可以从其他数据中重建,使用软引用-如果您保留对某些数据的规范实例的引用,或者您希望引用一个对象而不"拥有"它(因此防止它成为gc'd),使用弱引用。


在Java中,从一阶strongest weakest有:强,弱,软,和幻影

一个强大的参考是一个正常的参考对象,它是由被从收集的GC。没有垃圾collects IU。

a软使用的参考是由垃圾收集器的收集,但可能不会太小,直到它是需要记忆的。在OutOfMemoryError垃圾collects IU。

这是一个参考参考A弱引用的对象不正确A从收集的GC。垃圾collects IU当NO强参或软。

A是一个虚拟参考参考引用的对象是phantomly后它已finalized,但在其分配的内存已被再生。

JVM的类比:假设a是一个对象是一个王国,国王是一个王国,和GC attacker谁试图杀死的王国国王(对象)。

  • 当国王是不强,GC CAN杀死他。
  • 当国王是软,但GC攻击他。直到金规则与保护资源是可用的。
  • 当国王的GC是弱,但规则没有攻击他国的保护。
  • 当国王已经被杀的GC是幽灵,他通过他的灵魂,但国王是可用的。


弱引用docs.oracle.com http:/ / / / /文档/ JavaSE 1.5.0 Java API参考/ / /时间/ weakreference.html

原则是:weak reference相关的垃圾收集。通常,有一个或更多的reference对象将不使用的垃圾收集。上述原则是不适用的,当它是weak reference。如果对象与其他对象有唯一的弱引用,那么它的准备的垃圾收集。

让我们看下面的例子:我们有一个关键是在Map参考对象A的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

这是一个在WeakHashMapentries(key-to-value mappings)将被删除时,它不再是可能的,他们从Map检索。

让我展示一个例子weakhashmap上面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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使用。这可以由缠绕在一avoided weakreference对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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是略强,弱引用。软参考允许的垃圾收集到的垃圾收集器,但begs清除只读如果它没有其他选择。

在垃圾收集器收集的对象,不aggressively轻轻地到达和到达的方式它是一弱——它只会collects轻轻可达对象,如果它真的"需要"的记忆。软引用是一个垃圾收集器的方式说,"只要记忆不是太紧张,我想把这个对象周围。但如果内存变得很紧,去收集它,那我就交易。"垃圾收集器清除所有引用所需的软到在它可以OutOfMemoryError掷。


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

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


SoftReference是为缓存而设计的。当发现一个WeakReference引用了另一个无法到达的对象时,它将立即被清除。SoftReference可以保持原样。通常有一些算法与可用内存量和最后一次用于确定是否应该清除的时间有关。当前的Sun算法是为了清除引用,如果它没有被用在很多秒,因为Java堆上有3兆字节的内存(可配置的,服务器热点检查EDCOX1(ORDX1)第三条所设置的最大可能堆)。在抛出OutOfMemoryError之前,将清除SoftReferences,除非可以到达。


唯一真正的区别

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

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

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

软引用是有用的。内存敏感的缓存使用软引用,而不是weakreferences。Weakreference的唯一正确使用是观察GC运行。您可以通过创建一个新的weakreference来实现这一点,该weakreference的对象立即超出范围,然后尝试从weak_ref.get()中获取空值。当它是null时,您会了解到在这段时间内,GC运行。

对于weakreference的错误使用,列表是无止境的:

  • 实现priority-2软引用的一个糟糕的黑客程序,这样你就不必写一个,但它并没有按预期工作,因为缓存在每次GC运行时都会被清除,即使有空闲的内存。请参阅https://stackoverflow.com/a/3243242/632951了解PHAILS。(此外,如果您需要两个以上级别的缓存优先级呢?你还需要一个真正的图书馆。)

  • 将数据与现有类的对象相关联是一个糟糕的方法,但是当GC决定在创建weakreferences之后稍作休息时,它会导致内存泄漏(outofmemoryerror)。除此之外,它是非常丑陋的:更好的方法是使用元组。

  • 将数据与现有类的对象关联起来的一种糟糕的方法,在这种方法中,类具有使自己不可子类化的勇气,并用于需要调用的现有函数代码中。在这种情况下,正确的解决方案是要么编辑类并使其成为子类,要么编辑函数并使其采用接口而不是类,或者使用可选函数。


本文对理解强、软、弱和幻象的参考文献有很大帮助。

给你一个总结,

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

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

所以你可以说,强引用具有终极的能力(GC永远无法收集到)。

软引用比弱引用强大(因为它们可以在JVM耗尽内存之前退出GC循环)

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

餐厅类比

  • 服务员-气相色谱法
  • 你-堆中的对象
  • 餐厅区域/空间-堆空间
  • 新客户-餐厅需要桌子的新对象

现在,如果你是一个强大的客户(类似于强大的推荐人),那么即使一个新客户来了餐厅或发生了什么,你永远不会离开你的桌子(记忆区堆)。服务员无权告诉你(甚至要求你)离开餐厅。

如果你是一个软客户(类似于软参考),那么如果一个新客户来到餐厅,服务员不会要求你离开桌子,除非没有其他空桌子来容纳新客户。(换言之,只有当新客户进来时,服务生才会要求您离开桌子,而这个新客户没有其他的桌子了)

如果你是一个软弱的顾客(类似于软弱的推荐人),那么服务员可以(在任何时候)随意要求你离开餐馆:p


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

  • 强可访问对象—GC不会收集(回收)此类对象占用的内存。这些可以通过根节点或另一个强可访问对象(即通过局部变量、类变量、实例变量等)访问。
  • 软访问对象—GC可能会根据内存争用情况尝试收集此类对象。这些可以通过一个或多个软引用对象从根目录访问
  • 弱可访问对象-GC必须收集此类对象。这些可以通过一个或多个弱引用对象从根目录访问
  • 可恢复对象—GC已经在收集这些对象。但他们可能会回到其中一个州——通过执行某个最后定稿人来实现强/软/弱
  • 幻象可访问对象-GC已经在收集这些对象的过程中,并且已确定任何终结器都无法恢复(如果它本身声明了finalize()方法,则其终结器将已运行)。这些可以通过一个或多个幻象引用对象从根目录访问
  • 不可到达的物体-物体既不是强、软、弱,也不是幻影可到达的,也不是可恢复的。这些物品已准备好复垦。
  • 更多详情:https://www.artima.com/insidejvm/ed2/gc16.html?崩溃


    weakreference:在每个GC循环(次要或完整)中收集仅弱引用的对象。

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

  • -xx:softreflupolicymspemb=n标志(默认值为1000,即1秒)

  • 堆中的可用内存量。

    例子:

    • 堆有10MB的可用空间(在完全GC之后);
    • -xx:软反射系数mspermb=1000

    如果上次访问对象的时间大于10秒,则只由SoftReference引用的对象将被收集。


  • 应该知道,弱引用对象只有在只有弱引用时才会被收集。如果它有这么多强引用,那么不管它有多少弱引用,都不会收集到它。