我花了一些时间回到这个问题并获取所有可能的信息以了解它是如何工作的,并查看语句“如果您有一个引用已被另一个活动替换的活动的对象,那么您有内存泄漏”是真的。
首先,我决定运行一些代码来查看内存的行为。我使用了一个简单的 MVP 项目。
我做的第一件事是在调用 onDestroy 方法后在我的演示者中保留对活动的引用:
public abstract class BasePresenter<T> {
//Activity or Fragment attached to Presenter
protected T view;
public void onViewCreated(T view) {
this.view = view;
}
public void onStart() {
}
public void onResume() {
}
public void onPause() {
}
public void onStop(){
}
public void onDestroyed() {
// view = null;
}
}
然后我打开了“不在内存中保留活动”选项并重新创建了几次活动。
当我转储内存时,我看到了该活动的多个实例,但在使用 android 内存分析器选项调用垃圾收集器后,它们消失了(正如您所知,由于性能问题,每次都不会调用 GC,只是在需要)。
因此,在这种情况下,“如果您有一个对象引用的 Activity 已被另一个 Activity 替换,那么您就有内存泄漏”这句话是不正确的,或者至少它是不完整的。为了获得内存泄漏,该依赖图需要被 GC 根引用。
然后我决定在 onDestroy 中取消注释该行:
public void onDestroyed() {
view = null;
}
并且在我的片段中有一个对视图的静态引用(视图对创建它们的活动有一个引用)
private static View viewLeak;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
progressBar = view.findViewById(R.id.progress);
if(viewLeak == null){
viewLeak = progressBar;
}
}
再次,我重复了重新创建活动的过程,在这种情况下,我有同一个活动的多个实例(两个实例:一个被积极使用,另一个被静态视图引用)。当然,我调用了垃圾收集器,但该活动的额外实例保留在内存中。这里的变化是,在这种情况下,我们有一个 GC 根,它是静态变量:
静态变量由它们的类引用。这一事实使它们成为事实上的 GC 根源。 Source
当然,在多种情况下您可以获得 CG 根,因此在多种情况下您可能会出现内存泄漏。
我希望这可以帮助您澄清一些与 Java 中的内存泄漏相关的概念,就像它对我所做的那样。
有助于理解这一点的其他来源是:
LINK1, LINK2, LINK3
新内容:
这是来自 google I/O 的 video 谈论内存泄漏。请注意,当他说“具有 Activity 引用的长寿命对象”时 - 分钟 25:30。