【问题标题】:Android OS 6.0 nulling static variablesAndroid OS 6.0 清空静态变量
【发布时间】:2017-06-01 18:06:54
【问题描述】:

我在 Google Play 中有一堆痕迹,其中应用程序类的静态成员似乎为空。

我发现的所有相关帖子都是关于存储数据的,但这些变量不是数据,它们是 3rd 方 SDK 实例或其他与应用程序一起使用单例模式的关键对象。

Activity 类中使用的数据存储在数据库中,并且没有使用静态引用。

这些痕迹根本不会报告给 Fabric,这很奇怪,因为它是在 Application onCreate 方法中初始化的。

FirebaseMessagingService onMessageReceived 方法被触发时,跟踪表明静态变量为空,我需要将消息传递给第 3 方 SDK,但由于该实例为空,因此应用程序崩溃。

仅在 Android OS 6.0 中看到的痕迹

对于如何处理这个操作系统版本如此激进地清空静态成员,有什么解决方案吗?

谢谢。

这是我使用的最小示例代码:

应用类:

@Override
public void onCreate() {
    Engine.init();
}

引擎类:

private static Engine sInstance;

private 3rdParty m3rdParty;

private Engine() {
    m3rdParty = new 3rdParty();
}

public static void init() {
    if (sInstance == null) {
        sInstance = new Engine();
    }
}

public static onMessageReceived(RemoteMessage remoteMessage) {
    sInstance.m3rdParty.onMessageReceived(remoteMessage);
    // Above line crashes with NPE, sEngine or m3rdParty is never set to null in code
}

扩展 FirebaseMessagingService:

public void onMessageReceived(RemoteMessage remoteMessage) {
    Engine.onMessageReceived(remoteMessage);
}

【问题讨论】:

  • Android 不会清空静态字段。您能否发布您的 Application 课程以及这些单例如何初始化的详细信息?
  • 在一个地方看起来你的单身人士被命名为sEngine;在另一个,sInstance。这可能是问题吗?
  • 你的单例不是线程安全的,但如果你只在主线程中访问它就不需要了。您是否从发布的代码中删除了任何异步内容?
  • @KevinKrumwiede 抱歉打错了,你能告诉我更多关于这个线程安全的信息吗?
  • 因为sInstance不是finalvolatile,所以如果你设置在一个线程(这里是主线程)中,在另一个线程中读取,另一个线程不是保证看到你写的值。但是不是线程安全的代码几乎总是可以工作,这就是线程安全漏洞难以识别的原因。

标签: android android-6.0-marshmallow low-memory


【解决方案1】:

对于如何处理这个操作系统版本如此激进地归零静态成员,有什么解决方案吗?

“操作系统”不是“将静态成员归零”。最有可能的是,您的进程被终止,无论是由于内存不足还是用户操作(例如,将您的任务从概览屏幕上滑出)。这是完全正常的。

我说“最有可能”,因为您的问题不包含minimal, complete, and verifiable example、堆栈跟踪和相关源代码,因此我不能排除其他可能性。例如,如果您的代码在某些条件下将null 分配给那些static 字段,那么这些条件可能在您不期望的情况下得到满足。

【讨论】:

  • 发布了我的应用程序类、引擎类和推送服务如何交互的代码。那么如果静态成员从不为空,那么静态对象中的非静态成员是否可以为空?
  • @Niko:仅当您将null 分配给它时。也许有人正在使用您的应用程序的黑客版本,他们禁用了您的Application。如果这段代码是真实的,我会摆脱Engine.init() 并使用a proper thread-safe lazy-initalization pattern
  • 有数百条痕迹指向同一痕迹,并且它们都具有共同的 OS 6.0(LG、索尼、三星 + 其他制造商)。所以我相信上面的代码有问题,或者那个特定的操作系统版本有什么奇怪的地方。
  • 我可以改变 Engine 类的模式,但是我仍然不知道上面的代码在收到推送消息并调用 Engine.onMessageReceived() 时导致 NPE 有什么问题。
  • @Niko:我将首先测试您的代码,看看它在您的进程终止时的行为。您可以从 Android Studio 的 Monitor 工具终止您的进程(工具条中带有 X 的圆圈)。然后,向您的应用发送 FCM 消息,看看会发生什么。顺便说一句,如果您使用的是 multidex,您可能需要重新排序您的一些内容,以便 FCM 代码和 Engine 代码在同一个 DEX 文件中。我没怎么玩过multidex,但我似乎记得一些关于将常见的初始化东西放在一起的讨论。
猜你喜欢
  • 2016-05-19
  • 2014-12-26
  • 1970-01-01
  • 2012-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多