【发布时间】:2016-08-08 15:53:52
【问题描述】:
我正在为我公司的项目编写单元测试。最近,我们的 Jenkins 构建在单元测试 gradle 任务期间开始失败,出现OutOfMemory 异常(由超出GC overhead 限制或Java heap space 引起)。在我的本地机器上,单元测试成功,但有时甚至使用 3.5 GB 的内存。项目中有超过 1000 个测试,其中数百个创建 Activity 实例。
我做了一个堆转储(在大约 1000 次测试通过的那一刻),并使用 VisualVM 对其进行了检查。由于内存使用量和堆大小都在不断增加,我怀疑某处发生了内存泄漏。
我使用堆转储运行 Eclipse 内存分析器,#1 泄漏嫌疑人有很多 ReceiverDispatcher 实例,其中大约 255k(使用 > 500 MB 的内存)。此外,堆包含相同数量的 IntentReceiverLeaked 实例,略多 (258k) shadowBroadcastReceiver 实例,少两倍(约 127k)AccessibilityManagerService 和 LockPatternUtils 实例。
这对我来说很奇怪,因为我发现只有一个 BroadcastReceiver 在项目中动态注册(在 MainActivity 中),并且它在 Activity 的 onDestroy() 方法中被正确取消注册。
由于转储中大约有 300 个 Activity 实例,我怀疑泄漏的 Activity 是导致泄漏的主要原因。此外,Eclipse Memory Analyzer 将ShadowContextImpl 列为#2 问题嫌疑人,其实例略多于活动(但使用了大约 500 MB 的内存)。
测试中的Activity是使用Robolectric.setupActivity()创建的,相关的生命周期方法在tearDown()上调用
//Android Annotations are in use
protected ActivityController<MainActivity_> activityController;
protected MainActivity_ mainActivity;
@Before
public void setUp() throws Exception {
activityController = Robolectric.buildActivity(MainActivity_.class).setup();
mainActivity = activityController.get();
}
@After
public void tearDown() throws Exception {
try {
if (activityController != null) {
activityController.pause()
.stop()
.destroy();
}
} catch (Throwable th){}
mainActivity = null;
activityController = null;
}
对于 Fragment 相关的测试,Fragment 以常规方式创建并附加到 Activity(而不是使用 FragmentTestUtil)
public static void startFragment(Fragment fragment, FragmentActivity activity) {
shadowOf(Looper.getMainLooper()).pause();
FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(fragment, null);
fragmentTransaction.commitAllowingStateLoss();
shadowOf(Looper.getMainLooper()).runToEndOfTasks();
}
(...)
Activity activity = Robolectric.setupActivity(MainActivity_.class);
MyFragment fragment = MyFragment_.builder().build();
startFragment(fragment, activity);
(...)
这些泄漏的原因可能是什么(以及如何解决)?启动活动和片段的方式是否与泄漏有关?
【问题讨论】:
-
嘿 Piotr,这是一个长期存在的问题 github.com/robolectric/robolectric/issues/1700。不幸的是,它还没有修复。我会在那里添加你的发现
-
谢谢,我会告诉 Robolectric 团队这件事。希望对解决问题有所帮助。
标签: android memory-leaks robolectric