首页 文章

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

提问于
浏览

11 回答

  • 840

    来自Understanding Weak References,来自Ethan Nicholas:

    弱引用弱引用,简单地说,是一个不足以强制对象保留在内存中的引用 . 弱引用允许您利用垃圾收集器为您确定可达性的能力,因此您不必自己执行此操作 . 你创建一个像这样的弱引用:WeakReference weakWidget = new WeakReference(widget);
    然后在代码的其他地方你可以使用weakWidget.get()来获取实际的Widget对象 . 当然,弱引用不足以阻止垃圾收集,因此您可能会发现(如果没有对小部件的强引用)weakWidget.get()突然开始返回null . ...软引用软引用与弱引用完全相同,只是它不太愿意丢弃它引用的对象 . 一个只能弱到达的对象(对它的最强引用是WeakReferences)将在下一个垃圾收集周期被丢弃,但是一个可以轻松到达的对象通常会暂停一段时间 . SoftReferences的行为不需要与WeakReferences有任何不同,但实际上,只要内存供应充足,就可以保留软可访问对象 . 这使得它们成为缓存的良好基础,例如上面描述的图像缓存,因为您可以让垃圾收集器担心对象的可达性(永远不会从缓存中移除强可达对象)以及它有多糟糕需要他们消耗的记忆 .

    Peter Kessler在评论中补充道:

    Sun JRE确实以不同于WeakReferences的方式处理SoftReferences . 如果可用内存没有压力,我们会尝试保持SoftReference引用的对象 . 一个细节:“-client”和“-server”JRE的策略是不同的:-client JRE试图通过清除SoftReferences而不是扩展堆来保持您的足迹小,而-server JRE尝试保留您的通过优先扩展堆(如果可能)而不是清除SoftReferences来提高性能 . 一种尺寸并不适合所有人 .

  • 42

    急切地收集弱引用 . 如果GC发现某个对象是弱可达的(只能通过弱引用访问),它将立即清除对该对象的弱引用 . 因此,它们有助于保持对程序也保留(强烈引用)“关联信息”的对象的引用,例如关于类的缓存反射信息,或对象的包装器等 . 任何使得在它与之关联的对象之后保持不变是GC-ed . 当弱引用被清除时,它会在代码轮询某个地方的引用队列中排队,并且它也会丢弃关联的对象 . 也就是说,您保留有关对象的额外信息,但是一旦它引用的对象消失就不需要该信息 . 实际上,在某些情况下,您甚至可以继承WeakReference,并在WeakReference子类的字段中保留有关该对象的相关额外信息 . WeakReference的另一个典型用法是与Maps一起保存规范实例 .

    另一方面,SoftReferences适用于缓存外部可再生资源,因为GC通常会延迟清除它们 . 虽然在抛出OutOfMemoryError之前所有SoftReferences都会被清除,但是理论上它们不会导致OOME [*] .

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

    现在为[*] . 保持SoftReference本身不会导致OOME . 另一方面,如果您错误地将SoftReference用于任务,则应使用WeakReference(即,您以某种方式强烈引用与Object关联的信息,并在Reference对象被清除时丢弃它),您可以运行到OOME中轮询ReferenceQueue并丢弃关联对象的代码可能不会及时运行 .

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

  • 109

    In Java ;从最强到最弱的顺序,有:强,柔软,弱和幻影

    Strong reference 是一个普通引用,用于保护GC引用的引用对象 . 即从不垃圾收集 .

    Soft reference 符合垃圾收集器的收集条件,但在需要内存之前可能不会收集 . 即垃圾在 OutOfMemoryError 之前收集 .

    Weak reference 是一个不保护GC引用的引用对象的引用 . 即没有强力或软质参考时垃圾收集 .

    Phantom reference 是一个对象的引用,它在完成后被引用,但在它已分配的内存被回收之前被引用 .

    Source

    Analogy: 假设JVM是一个王国,对象是王国的王者,GC是试图杀死国王(对象)的王国的攻击者 .

    • 当King为 Strong 时,GC无法杀死他 .

    • 当King为 Soft 时,GC攻击他,但是国王统治了王国,直到有资源可用 .

    • 当国王 Weak 时,GC攻击他,但在没有保护的情况下统治王国 .

    • 当国王 Phantom 时,GC已经杀了他,但国王可以通过他的灵魂获得 .

  • 68

    Weak Reference http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html

    Principle: weak reference 与垃圾收集有关 . 通常,具有一个或多个 reference 的对象将不符合垃圾回收的条件 .
    weak reference 时,上述原则不适用 . 如果一个对象只有其他对象的弱引用,那么它就可以进行垃圾回收了 .

    让我们看看下面的例子:我们有一个带有对象的 Map ,其中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 是当无法再从 Map 检索条目( key-to-value mappings )时将删除的条目 .

    让我用 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: 取得 20 calls to System.gc() 导致 aMap size 为:0 .

    WeakHashMap 只有对键的弱引用,而不像其他 Map 类那样强引用 . 尽管您使用了 WeakHashMap ,但在强烈引用值或键时,您必须注意这些情况 . 这可以通过将对象包装在_566046中来避免 .

    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 Reference 略强于弱参考 . 软引用允许垃圾收集,但只有在没有其他选项时才请求垃圾收集器清除它 .

    垃圾收集器不会像对待弱可达对象那样积极地收集可轻松访问的对象 - 而是只收集可轻松访问的对象(如果它真的是内存) . 软引用是对垃圾收集器说的一种方式,"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."垃圾收集器需要清除所有软引用才能抛出 OutOfMemoryError .

  • 3

    软参考和弱参考之间唯一真正的区别是

    垃圾收集器使用算法来决定是否回收可轻松访问的对象,但始终回收弱可达对象 .

  • 1

    SoftReference 专为缓存而设计 . 当发现 WeakReference 引用了其他无法访问的对象时,它将立即被清除 . SoftReference 可以保留原样 . 通常,存在一些与空闲存储量和最后用于确定是否应该被清除的时间有关的算法 . 当前的Sun算法是清除引用,如果它没有在Java堆上有多兆字节的可用内存时使用(可配置,服务器HotSpot检查由 -Xmx 设置的最大可能堆) . 除非另有说明,否则 SoftReference 将在抛出 OutOfMemoryError 之前被清除 .

  • 191

    唯一真正的区别

    the doc,松散的WeakReferences must 由正在运行的GC清除 .

    每个the doc,松散的SoftReferences must 在抛出OOM之前被清除 .

    这是唯一真正的区别 . 其他一切都不是 Contract 的一部分 . (我假设最新的文档是 Contract 的 . )

    SoftReferences are useful. 内存敏感的缓存使用SoftReferences,而不是WeakReferences .


    WeakReference的唯一 proper 用法是观察GC运行 . 你通过创建一个新的WeakReference来做到这一点,它的对象会立即超出范围,然后尝试从 weak_ref.get() 中获取null . 当它是 null 时,你会发现在这段时间内,GC运行了 .

    至于 incorrect 使用WeakReference,列表是无止境的:

    • 一个糟糕的黑客来实现优先级2软引用,这样你就不必写一个, yet 它不能按预期工作,因为缓存将在 every GC运行时被清除,即使有空闲内存 . 有关phails,请参阅https://stackoverflow.com/a/3243242/632951 . (此外,如果您需要超过2级缓存优先级怎么办?您仍然需要一个真正的库 . )

    • 糟糕的黑客将数据与现有类的对象关联, yet 它当您的GC决定在创建弱引用后休息时,会创建内存泄漏(OutOfMemoryError) . 此外,它超出了丑陋:更好的方法是使用元组 .

    • 糟糕的黑客将数据与现有类的对象相关联,其中类具有使其自身不可子类化的神经,并且在您需要调用的_566072中使用 . 在这种情况下,正确的解决方案是编辑类并使其成为子类,或编辑函数并使其采用接口而不是类,或使用替代函数 .

  • 22

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

    • Strong ly可达对象 - GC will not collect( reclaim the memory occupied by )这种对象 . 这些是 reachable via a root node or another strongly reachable object (即通过局部变量,类变量,实例变量等)

    • Soft lyachable对象 - GC may attempt 根据内存争用收集此类对象 . 这些可以通过一个或多个来自根目录 soft reference objects

    • Weak ly可达对象 - GC must 收集此类对象 . 这些可以通过一个或多个来自根目录 weak reference objects

    • Resurrect-able 个对象 - GC已经在收集这些对象 . 但 they may go back to one of the states - Strong/Soft/Weak 由执行一些终结器

    • Phantom ly可达对象 - 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) . 这些可以通过一个或多个来自根目录 phantom reference objects

    • Unreachable object - 一个对象既不强烈,柔和,弱,也不是幻像可达,并且不可复原 . 这些对象已准备好进行回收

    有关详细信息:https://www.artima.com/insidejvm/ed2/gc16.html«崩溃

  • 0

    这个article可以非常有助于理解强,弱,弱和幻像参考 .


    为了给你一个总结,

    如果您只有 weak references 到一个对象(没有强引用),那么GC将在下一个GC循环中回收该对象 .

    如果您只有 soft references 到一个对象(没有强引用),那么只有当JVM内存不足时,GC才会回收该对象 .


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

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

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


    Restaurant Analogy

    • 服务员 - GC

    • 你 - 堆中的对象

    • 餐厅区/空间 - 堆空间

    • 新客户 - 需要餐厅餐桌的新对象

    现在,如果你是一个强大的客户(类似于强大的参考),那么即使一个新客户进入餐厅或者什么如此开心,你永远不会离开你的 table (堆上的内存区域) . 服务员无权告诉您(甚至要求您)离开餐厅 .

    如果您是软客户(类似于软参考),那么如果新客户进入餐厅,服务员将不会要求您离开餐桌,除非没有其他空桌来容纳新客户 . (换句话说,只有当新客户介入并且没有其他表留给这位新客户时,服务员才会要求您离开 table )

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

  • 6

    应该意识到,只有弱参考对象才会收集弱引用对象 . 如果它有一个强引用,那么无论它有多少弱引用,它都不会被收集 .

  • 0

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

    SoftReference :只收集软引用的对象取决于:

    • -XX:SoftRefLRUPolicyMSPerMB = N标志(默认值为1000,又称1秒)

    • 堆中的可用内存量 .

    例:

    • 堆有10MB的可用空间(完全GC后);

    • -XX:SoftRefLRUPolicyMSPerMB = 1000

    然后,如果上次访问的对象大于10秒,则将收集仅由SoftReference引用的对象 .

相关问题