在对Google Cardboard应用程序进行性能分析时,每次离开带有3D图形的活动时,我都会发现内存泄漏非常大(15Mb!)。

经过漫长而艰苦的调查,我发现问题的根源是每次我关闭CardboardActivity子类时都发生的Context leak

该解决方案可以在接受的答案中找到*

*哇...这很尴尬...对于任何(有经验的)审稿人都需要注意:我正在写一个我已经知道答案的问题:我是否应该为样式做一些事情,例如添加一些假的悬念? (“我们的英雄会胜利吗?!在接受的答案中找到答案!”),就像在旧的蝙蝠侠电视连续剧中一样?

最佳答案

在对我的CardboardActivity子类进行切块和切片之后,直到除了基类之外别无其他,我不得不得出结论,即基类本身正在泄漏上下文。

我在网上搜索并找到this post,它解释了有问题的活动如何通过未能向类的私有实例取消注册侦听器而泄漏了上下文。

尝试手动(使用反射)调用所述方法时,我发现在当前版本的Cardboard SDK(撰写本文时为0.5.4)中,该字段不再存在。

长话短说:所有传感器现在都由未记录的(公开的)SensorConnection类处理,该类在CardboardActivity中实例化为sensorConnection字段,但仍然受到我的第一个链接中详细介绍的错误的困扰。

这使我想到了这个解决方案:


通过反射获取sensorConnection中的CardboardActivity字段
再次通过反射使用它来获取magneticSensor字段
setOnCardboardTheaterListener参数调用null,以清除在Context Activity方法中包含对onDestroy的引用的绑定。


归结为以下代码:

private void workAroundLeak() {
    try {
        // Get the sensor Connection
        Class<?> c1 = Class.forName("com.google.vrtoolkit.cardboard.CardboardActivity");
        Field sensorsField = c1.getDeclaredField("sensorConnection");
        sensorsField.setAccessible(true);
        SensorConnection sc = (SensorConnection) sensorsField.get(this);
        if(sc == null) return;

        // Get the magnetSensor
        Class<?> c2 = Class.forName("com.google.vrtoolkit.cardboard.sensors.SensorConnection");
        Field magnetField = c2.getDeclaredField("magnetSensor");
        magnetField.setAccessible(true);
        MagnetSensor ms = (MagnetSensor) magnetField.get(sc);
        if(ms == null) return;

        ms.setOnCardboardTriggerListener(null);
    } catch(Exception e) {}
}

@Override
protected void onDestroy() {
    workAroundLeak();
    super.onDestroy();
}


完全解决了问题。

明智的一句话:由于此解决方案依赖于反思,因此一旦Google更新SDK(可能以一种干净的方式解决),它可能会崩溃(可能不会造成任何后果,但不会造成任何后果)。

希望这可以帮助某人

关于android - CardboardActivity中的内存泄漏,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31038532/

10-13 04:13