Mat*_*ias 29 java singleton android garbage-collection classloader
我有一个特定的问题,如何在Android中运行类加载/垃圾收集.我们现在偶然发现了几次这个问题,据我所知,Android在这里与普通的JVM不同.
问题在于:我们目前正在尝试减少应用程序中的单例类,以支持单个根工厂单例,其唯一目的是管理其他管理器类.如果你愿意的话,是一名顶级经理.这使我们可以轻松地替换测试中的实现,而无需选择完整的DI解决方案,因为所有活动和服务共享对该根工厂的相同引用.
这是它的样子:
public class RootFactory {
private static volatile RootFactory instance;
@SuppressWarnings("unused")
private Context context; // I'd like to keep this for now
private volatile LanguageSupport languageSupport;
private volatile Preferences preferences;
private volatile LoginManager loginManager;
private volatile TaskManager taskManager;
private volatile PositionProvider positionManager;
private volatile SimpleDataStorage simpleDataStorage;
public static RootFactory initialize(Context context) {
instance = new RootFactory(context);
return instance;
}
private RootFactory(Context context) {
this.context = context;
}
public static RootFactory getInstance() {
return instance;
}
public LanguageSupport getLanguageSupport() {
return languageSupport;
}
public void setLanguageSupport(LanguageSupport languageSupport) {
this.languageSupport = languageSupport;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
initialize被调用一次,Application.onCreate即在任何活动或服务启动之前.现在,问题出现了:即使在同一个线程上调用,该getInstance方法有时也会回来null!听起来这不是一个能见度问题; 相反,类级别上的静态单例引用保持似乎实际上已被垃圾收集器清除.也许我在这里得出结论,但这可能是因为Android垃圾收集器或类加载机制实际上可以在内存稀缺时卸载类,在这种情况下,对单例实例的唯一引用将消失?我并不是真的深入了解Java的内存模型,但我认为这不应该发生,否则这种实现单例的常用方法对任何JVM都不起作用吗?
知道为什么会发生这种情况吗?
PS:可以通过在单个应用程序实例上保留"全局"引用来解决此问题.事实证明,当应用程序必须在应用程序的整个生命周期内保持对象时,这是可靠的.
UPDATE
显然我在这里使用volatile会引起一些混乱.我的目的是确保静态引用的当前状态始终对访问它的所有线程可见.我必须这样做,因为我正在编写并从多个线程中读取该引用:在一个普通的应用程序中,只在主应用程序线程中运行,但在一个检测测试运行中,对象被mocks替换,我从检测线程并在UI线程上读取它.我也可以同步调用getInstance,但这更昂贵,因为它需要声明对象锁定.请参阅在Java中实现单例模式的有效方法是什么?有关此问题的更详细讨论.
您(@Matthias)和Mark Murphy(@CommonsWare)的说法都是正确的,但要点似乎很失落。(对的使用volatile是正确的,不会卸载类。)
问题的症结在于从何initialize而来。
我认为这是正在发生的事情:
Activity ProcessApplication和ActivitygetInstance这将返回null,因为initialize当时不叫如果我错了纠正我。
更新:
我的假设- initialize从Activity *调用-在这种情况下似乎是错误的。但是,我将保留这个答案,因为这种情况是错误的常见来源。
只要系统愿意并且您的应用程序不是顶级的(用户没有显式运行它),静态引用就会被清除。每当您的应用程序最小化并且操作系统需要更多内存时,它就会杀死您的应用程序或将其序列化到固定存储上以供以后使用,但在这两种情况下静态变量都会被删除。此外,每当您的应用程序出现Force Close错误时,所有静态信息也会被删除。根据我的经验,我发现在应用程序对象中使用变量总是比静态变量更好。
| 归档时间: |
|
| 查看次数: |
5948 次 |
| 最近记录: |