CardboardActivity 中的内存泄漏
Memory leak in CardboardActivity
在分析我的 Google Cardboard 应用程序时,我发现每次离开 activity 3D 图形时都会发生非常大的内存泄漏(15Mb!)。
经过漫长而痛苦的调查,我发现问题的根源是每次关闭 CardboardActivity
子类时发生的 Context leak。
解决方案可以在接受的答案中找到*
*
哇...这很尴尬...注意任何类型(和有经验)审阅者:我正在写一个问题给我认识的人已经回答了:我是否应该为风格做些事情,比如添加一些假悬念("will our heroes prevail?! Find out in the accepted answer!"),就像在旧的蝙蝠侠电视剧中一样?
在对我的 CardboardActivity
subclass 进行切块和切片后,直到只剩下底座 class,我不得不得出结论,底座 class 本身正在泄漏上下文。
我在网上搜索并发现 this post 解释了有问题的 activity 是如何通过未能注销 class 的私有实例的侦听器来泄露上下文的。
在尝试手动调用上述方法(使用反射)时,我发现在当前版本的 Cardboard SDK(撰写本文时为 0.5.4)中,该字段不再存在。
长话短说:所有传感器现在都由未记录(尚未 public)SensorConnection class 在 CardboardActivity
中作为 sensorConnection
字段实例化,它仍然受到我第一个 link.
中详述的错误的困扰
这让我想到了这个解决方案:
- 通过反射获取
CardboardActivity
中的sensorConnection
字段
- 使用它来获取
magneticSensor
字段,再次通过反射
- 使用
null
参数调用 setOnCardboardTheaterListener
,以清除绑定 Activity
onDestroy
方法中对 Context
的引用。
归结为以下代码:
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(可能以干净的方式解决问题)。
希望这对某人有所帮助
在分析我的 Google Cardboard 应用程序时,我发现每次离开 activity 3D 图形时都会发生非常大的内存泄漏(15Mb!)。
经过漫长而痛苦的调查,我发现问题的根源是每次关闭 CardboardActivity
子类时发生的 Context leak。
解决方案可以在接受的答案中找到*
*
哇...这很尴尬...注意任何类型(和有经验)审阅者:我正在写一个问题给我认识的人已经回答了:我是否应该为风格做些事情,比如添加一些假悬念("will our heroes prevail?! Find out in the accepted answer!"),就像在旧的蝙蝠侠电视剧中一样?
在对我的 CardboardActivity
subclass 进行切块和切片后,直到只剩下底座 class,我不得不得出结论,底座 class 本身正在泄漏上下文。
我在网上搜索并发现 this post 解释了有问题的 activity 是如何通过未能注销 class 的私有实例的侦听器来泄露上下文的。
在尝试手动调用上述方法(使用反射)时,我发现在当前版本的 Cardboard SDK(撰写本文时为 0.5.4)中,该字段不再存在。
长话短说:所有传感器现在都由未记录(尚未 public)SensorConnection class 在 CardboardActivity
中作为 sensorConnection
字段实例化,它仍然受到我第一个 link.
这让我想到了这个解决方案:
- 通过反射获取
CardboardActivity
中的sensorConnection
字段 - 使用它来获取
magneticSensor
字段,再次通过反射 - 使用
null
参数调用setOnCardboardTheaterListener
,以清除绑定Activity
onDestroy
方法中对Context
的引用。
归结为以下代码:
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(可能以干净的方式解决问题)。
希望这对某人有所帮助