gpt4 book ai didi

java - 静态引用被清除——如果未使用,Android 是否会在运行时卸载类?

转载 作者:IT老高 更新时间:2023-10-28 21:09:10 25 4
gpt4 key购买 nike

我有一个关于类加载/垃圾收集如何在 Android 中工作的问题。我们已经多次偶然发现这个问题,据我所知,Android 在这里的行为与普通 JVM 不同。

问题是这样的:我们目前正在尝试减少应用程序中的单例类,转而支持单个根工厂单例,其唯一目的是管理其他管理器类。如果你愿意的话,一个顶级经理。这使我们无需选择完整的 DI 解决方案即可轻松替换测试中的实现,因为所有 Activity 和服务共享对该根工厂的相同引用。

它是这样的:

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;
}

// ...
}

initialize 被调用一次,在 Application.onCreate 中,即 任何 Activity 或 Service 启动之前。现在,问题来了:getInstance 方法有时会以 null 的形式返回——即使在同一个线程上调用也是如此!听起来这不是能见度问题。相反,类级别的静态单例引用保留似乎实际上已被垃圾收集器清除。也许我在这里草率下结论,但这可能是因为 Android 垃圾收集器或类加载机制实际上可以在内存不足时 unload 类,在这种情况下,对单例实例的唯一引用将消失离开?我对 Java 的内存模型并不是很深入,但我认为这不应该发生,否则这种实现单例的常用方法在任何 JVM 上都不起作用,对吧?

知道为什么会这样吗?

PS:可以通过在单个应用程序实例上保留“全局”引用来解决此问题。事实证明,当人们必须在应用程序的整个生命周期中始终保持对象时,这是可靠的。

更新

显然我在这里使用 volatile 引起了一些困惑。我的目的是确保静态引用的当前状态对所有访问它的线程始终可见。我必须这样做,因为我从多个线程中编写和读取该引用:在一个普通的应用程序中只在主应用程序线程中运行,但在一个仪器测试运行中,对象被替换为模拟,我从检测线程并在 UI 线程上读取它。我也可以同步对 getInstance 的调用,但这更昂贵,因为它需要声明对象锁。见 What is an efficient way to implement a singleton pattern in Java?有关此问题的更详细讨论。

最佳答案

您 (@Matthias) 和 Mark Murphy (@CommonsWare) 的说法都是正确的,但要点似乎丢失了。 (volatile的使用是正确的,类没有被卸载。)

问题的关键是从哪里调用 initialize

这是我认为正在发生的事情:

  • 您正在从 Activity *
  • 调用初始化
  • Android 需要更多内存,杀死整个进程
  • Android重启Application和最上面的Activity
  • 您调用 getInstance 将返回 null,因为未调用 initialize

如果我错了,请纠正我。


更新:
我的假设 - initialize 是从 Activity * 调用的 - 在这种情况下似乎是错误的。但是,我将保留这个答案,因为这种情况是常见的错误来源。

关于java - 静态引用被清除——如果未使用,Android 是否会在运行时卸载类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5105097/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com