【问题标题】:Self releasing (reference counting) singelton自释放(引用计数)单例
【发布时间】:2013-12-19 08:28:37
【问题描述】:

考虑以下场景: 您有一个代表某种数据提供者的单例类。 这个单例类分配了大量的内存,你希望它在没有人使用他的时候释放它分配的内存。 流程:

  1. A 类调用 getInstance 并使用单例(这是第一次调用 getInstance 并且单例类分配了巨大的内存块)
  2. B 类调用 getInstance 并使用单例
  3. A 类和 B 类“死亡”(现在没有人使用单例)
  4. 程序仍在运行,但未释放单例的内存。

您如何建议实现在第 3 阶段(A 类和 B 类“死”)将释放内存的单例(我知道 java 使用垃圾收集但仍然可以说我想要以下内存 = null)。

PS 我不想在停止使用单例时强制每个使用单例调用的类在单例上释放。我希望单身人士自己处理“释放”内存。

【问题讨论】:

    标签: java memory-management garbage-collection singleton


    【解决方案1】:

    你能做的是

    • 仅在第一次请求时创建单例。
    • 将其存储在WeakReference 中。只有在其他地方仍然有“强”引用时,它才会在 GC 之后保持活动状态。

    如果WeakReference.get()null,这意味着它被收集了,因为没有人强烈使用它,另一个弱引用不计算在内。如果再次需要它,您需要重新创建它和WeakReference

    这样,

    public enum SingletonHolder{; // no instances
    
        private static WeakReference<MyType> ref = null;
    
        public static synchronized MyType getInstance() {
             MyType type = ref == null ? null : ref.get();
             if (type == null)
                 ref = new WeakReference<MyType>(type = new MyType());
             return type;
        }
    }
    

    顺便说一句,这假定需要此实例的实例保留对它的引用。这就是弱引用“知道”它仍然需要的方式。

    顺便说一句,如果它是单线程的,则不需要同步,但它应该是无害的。

    这意味着您应该仅在新实例第一次需要它时调用此方法,而不是每次都调用它,并且提高它的性能不应该有太大的区别,例如双重检查只会让它复杂化。

    【讨论】:

    • 嘿彼得,是的,我假设其他使用单例的类引用了单例类。我来自 C++ 世界,所以让我们说,当调用 A 被 GC 收集时,他是否不再引用单例类或 A 类应该专门调用:singleton = null ?
    • @JobNick 仅当 A 不再需要 Singleton 但您不希望它被收集时才应该这样做。如果您希望实例 A 在已被丢弃时被收集,则无需执行此操作。
    • 假设 GC 收集了引用 Singleton 对象的类 A,并且在某个时间点 GC 决定收集 Singleton。谁来分配: ref = null 或让 ref.get() 返回 null 所以下次有人想在收集后再次使用单例时,它将被重新分配?
    【解决方案2】:

    Design pattern: "Singleton" 的使用非常普遍,常见的实现是使用static reference

    这个实现的问题是很多时候它留下了没有使用的floating garbage

    例如: 一个singleton 包含一个DB connection pool,仅在应用程序启动时才需要用于配置加载。

    因此,更好的解决方案是扩展单例设计模式,称为WeakSingleton

    此模式符合预期,当对原始实例的所有其他引用都已过期时,该实例将被清除。

    这种模式在java中的实现非常简单,可以基于WeakReferences

    例如代码:

    public class WeakSingleton{
    
    static private WeakReference singleton; // instance
    
    public WeakSingleton getInstance(){
    
      WeakSingleton m = (WeakSingleton)singleton.get();
    
      if( m != null)
    
         return m;
    
      synchronized (WeakSingleton.class){
    
         m = (WeakSingleton)singleton.get();
    
         if( m != null)
    
        return m;       
    
        m = new WeakSingleton(); // creates new instnace 
    
        singleton = new WeakReference(m);
    
      } 
    
      return m;
    
     }
    
    }
    

    【讨论】:

    • 嘿,不使用线程时是否真的需要“双重检查”模式?
    • 否。使用枚举是最好的方法。这只是示例。让我编辑它
    猜你喜欢
    • 2013-05-15
    • 1970-01-01
    • 1970-01-01
    • 2012-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多