当前位置: 首页 > 知识库问答 >
问题:

Android、RxJava、MVP和内存泄漏

锺离宸
2023-03-14

我有一个创建Presenter实例的活动。在Presenter层中,我从存储库中获取一个可观察的实例。然后,我使用Subscriber的子类订阅Observable,然后将结果订阅对象添加到CompositeSubscription。因为调用订阅服务器的onNext()后,我需要修改活动,所以我还将Presenter的引用传递给订阅服务器。

现在,我想知道引用是如何工作的,什么时候才有资格进行垃圾收集。

示例1:使用Subscriber订阅Observable,并将订阅添加到CompositeSubscription。在调用订阅服务器的onNext()之前,父活动将触发其onPause()生命周期事件。它告诉演示者点击暂停()并调用CompositeSubscription上的clear()。

此时复合订阅、订阅者和可观察有资格获得GC吗?或者在Presenter的onPawn()方法中,我是否需要显式地将对可观察、订阅者和复合订阅的引用归零?

示例2:

与示例1类似,演示者订阅了一个可观察对象,在调用Subscriber的onNext()方法之前,活动会经过onPause(),但这次也会经过onResume()。

因此,就像示例1中一样,演示者在onPause()中对CompositeSubscription调用clear()。

然后在onResume中发生以下情况:Presenter之前将可观察缓存在单例类中,因此在onResume中它可以看到缓存中有一个可观察的,这意味着可观察的从未完成运行。因此,Presenter现在创建了一个新的订阅者实例和一个新的CompositeSubscription实例,并使用订阅者和CompositeSubscription的新实例订阅缓存的可观察的。

但是现在我的问题是,我引入了内存泄漏吗?Subscriber的第一个实例引用了Presenter。当onResume()被调用时,我创建了Subscriber的第二个实例,Presenter引用了这个新实例。那么Subscriber的第一个实例会发生什么呢?它符合GC的条件吗?还是因为它引用了演示者但不再有指向它的引用而导致内存泄漏?

class Presenter {
    private MyActivity mActivity;
    private Repository mRepository;
    private GlobalCache mGlobalCache;
    private CompositeSubscription mCompSub;

    public Presenter(MyActivity activity, Repository repository, GlobalCache globalCache) {
        mActivity = activity;
        mRepository = repository;
        mGlobalCache = globalCache;
    }

    public void doLongRunningThing() {
        Observable<Object> obs = mRepository.getObs();
             mGlobalCache.retain(obs);
             mCompSub = new CompositeSubscription();
             MySubscriber subscriber = new Subscriber(this);
             compSub.add(obs.subscribe(subscriber));
    }


    public void onResume() {
        if (mGlobalCache.getObs() != null) {
            Observable<Object> obs = mGlobalCache.getObs();
            mCompSub = new CompositeSubscription();
            MySubscriber subscriber = new Subscriber(this);
            compSub.add(obs.subscribe(subscriber));
        }
    }

    public void onPause() {
        if(mCompSub != null && mCompSub.hasSubscriptions()) {
            mCompSub.clear();
        }
    }

    public void onDestroy() {
        mActivity = null;
        mRepository = null;
        mGlobalCache = null;
    }

    public void handleResponse(Object object) {
        activity.setUiToSomeState();
    }

}

class MySubscriber extends Subscriber<Object> {
     private Presenter mPresenter;
     private GlobalCached mGlobalCache;

     public MySubscriber(Presenter presenter, GlobalCache globalCache) {
         mPresenter = presenter;
         mGlobalCache = globalCache;
     }

     onCompleted() {

     }

     onError() {

     }

     onNext(Object object) {
          mGlobalCache.clearObs();
          mPresenter.handleResponse(object);
     }
}

共有1个答案

危阳
2023-03-14

示例1:
假设您的意思是这里没有保存引用的“缓存”:
示例中没有泄漏。关于GC,订阅者对象可以被GC’d(释放),因为再也没有对象对其进行引用了,但是,CompositeSubscription引用由presenter持有,我假设该presenter由活动持有(对于Observable可能相同,示例中不清楚),所以当活动持有对该对象的引用时,它们的GC取决于它们的父活动。直到活动本身不再由任何人举办
(旁注:已完成的活动与暂停/停止的活动之间存在差异,在前一种情况下,系统将在不再需要此活动时尽快尝试GC,而在后一种情况下,只要有必要,系统将保留该活动)

示例2:
虽然您有一个(静态假设)缓存,但由于您在onPause取消了对可观察对象的订阅,可观察对象没有对演示者/活动的引用,因此不会发生活动泄漏。在现实生活场景中,这仍然取决于这个可观察对象或任何操作符应用于他的内容,这意味着如果链中的某个地方有活动/演示者对象的引用,则可能存在泄漏。

除此之外,我建议您始终进行测试,以确保没有遗漏任何内容,您可以使用adb dumpsys meminfo并观察活动的计数,简单的打开和关闭(完成)活动多次可以指示泄漏,此外,Square的优秀人员还提供了LeakCanary库,可以在调试时自动报告活动泄漏。

 类似资料:
  • 我担心从泄漏金丝雀回来的信息。它显示了在UI上声明的所有变量,如片段中的材料按钮、材料卡片视图、文本视图、图像视图等,都导致了内存泄漏。我不知道为什么会这样。

  • 问题内容: 我认为我的android应用正在泄漏内存。我不是绝对确定这是问题所在。 应用程序打开时经常崩溃,并且logcat尝试加载位图图像时会显示“内存不足”异常。 崩溃后,我重新打开了该应用程序,它运行正常。Logcat会显示许多“ gc”,并且JIT表会不时地向上调整大小,而不会向下调整,直到应用程序因内存不足错误而崩溃。 这听起来像是内存泄漏吗?如果是这样,我该如何定位和关闭泄漏点。 这是

  • 我正在Android应用程序中使用一些本机库,我想在某个时间点从内存中卸载它们。当装入本机库的类的类装入器被垃圾回收时,库被卸载。灵感:本土卸载。 如果ClassLoader用于加载某些类(可能导致内存泄漏),则不会收集垃圾。 本机库只能在应用程序中的一个ClassLoader中加载。如果仍然有旧的ClassLoader挂在内存中的某个地方,并且一个新的ClassLoader试图在某个时间点加载相

  • 我正在使用libgdx制作一个实时壁纸应用程序,根据时间改变资产。对于e、 g从早上6点到下午6点,我有“早上图形”,之后我有“晚上图形”,从下午6点到早上6点。 我构建资产的方式如下 我有12个AtlasRegion类型的静态数组,1个静态纹理区域变量和1个静态纹理变量。 我有两个静态函数load晨()和loadEnight()用于加载资产。 在funcions中,我加载如下 对于所有数组,如果

  • 本文向大家介绍Android 内存溢出和内存泄漏的问题,包括了Android 内存溢出和内存泄漏的问题的使用技巧和注意事项,需要的朋友参考一下 Android 内存溢出和内存泄漏的问题 在面试中,经常有面试官会问“你知道什么是内存溢出?什么是内存泄漏?怎么避免?”通过这篇文章,你可以回答出来了。 内存溢出 (OOM)是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;

  • 我正在玩rxjava,发现如果在活动被销毁之前没有完成订阅,则存在内存泄漏的风险,因为“可观察对象保留对上下文的引用”。如果订阅没有取消订阅,则此类情况的演示之一如下所示。已销毁(来源:https://github.com/dlew/android-subscription-leaks/blob/master/app/src/main/java/net/danlew/rxsubscriptions