rx android 内存泄露,你使用Rxjava时,内存泄漏了吗?

今天有位同学问了我一个问题,话说,问我

“有遇到网络请求一半,退出Activity造成的Theard泄露吗?已在销毁时调用了un了

我去查看了下rx的源码的unsubscribe方法,定位到一个实现类,NewThreadWorker的unsubscribe方法中,源码如下:

@Override

public void unsubscribe() {

isUnsubscribed = true;

executor.shutdownNow();

deregisterExecutor(executor);

}

@Override

public boolean isUnsubscribed() {

return isUnsubscribed;

}

这个shutdownNow()在java的注释中写的很清楚

There are no guarantees beyond best-effort attempts to stop* processing actively executing tasks.

public interface ExecutorService extends Executor {

/**

* Initiates an orderly shutdown in which previously submitted

* tasks are executed, but no new tasks will be accepted.

* Invocation has no additional effect if already shut down.

*

*

This method does not wait for previously submitted tasks to

* complete execution. Use {@link #awaitTermination awaitTermination}

* to do that.

*/

void shutdown();

/**

* Attempts to stop all actively executing tasks, halts the

* processing of waiting tasks, and returns a list of the tasks

* that were awaiting execution.

*

*

This method does not wait for actively executing tasks to

* terminate. Use {@link #awaitTermination awaitTermination} to

* do that.

*

*

There are no guarantees beyond best-effort attempts to stop

* processing actively executing tasks. For example, typical

* implementations will cancel via {@link Thread#interrupt}, so any

* task that fails to respond to interrupts may never terminate.

*

* @return list of tasks that never commenced execution

*/

List shutdownNow();

它只是尽量保证停止所有tasks,因为,如果耗时操作没有做完,finished掉activity,同时unsubscribe 掉Subscription的话,可能还有后台线程在做一些耗时任务。那么会不会造成内存泄露呢?

我觉得还是要源码来说说话吧

/**

* Unsubscribe from all of the subscriptions in the list, which stops the receipt of notifications on

* the associated {@code Subscriber}.

*/

@Override

public void unsubscribe() {

if (!unsubscribed) {

List list;

synchronized (this) {

if (unsubscribed) {

return;

}

unsubscribed = true;

list = subscriptions;

subscriptions = null;

}

// we will only get here once

unsubscribeFromAll(list);

}

}

private static void unsubscribeFromAll(Collection subscriptions) {

if (subscriptions == null) {

return;

}

List es = null;

for (Subscription s : subscriptions) {

try {

s.unsubscribe();

} catch (Throwable e) {

if (es == null) {

es = new ArrayList();

}

es.add(e);

}

}

Exceptions.throwIfAny(es);

}

实际上会做一些清除引用,暂停任务的操作。因此,一般来讲在activity的ondestroy中调用unsubscribe之后,是不会造成内存泄露的。但是真的是这样的吗?让我们来做做实验吧,结果说明一切。

为了能够更好的证明这一点,我还特意做了一个app demo去验证。

主要代码:

c720ec2b5383

secondActivity.png

c720ec2b5383

耗时任务rx封装

demo地址已经放到了github上:

启动app,首先进入的是MainActivity,然后,我们进入SecondActivity这时候,onresume执行,我们的任务也就开始了,稍微过几秒,我们退出SecondActivity,回到MainActivity,这之后,显然,SecondActivity的ondestory方法会被执行,我们可以发现日志也停止了打印。

c720ec2b5383

耗时任务正在执行

如上图所示,停留在了5就不在执行了。

这时候,我们GC一下,在导出hprof文件,注意,为什么要手动GC一下呢?因为android虚拟机去GC也是有策略的,有GC周期的。这时候可能并没有GC过,也就是说,SecondActivity的内存可能并没有被释放,但并不等于说,SecondActivity就泄露了,因为他也有可能是可以被GC的,只是还没有来得及被GC而已。总之,在导出hprof文件之前,最好先手动GC一下。就是下图那个车子,嗯,点一下吧,放心点。

c720ec2b5383

GC.png

然后熟悉查看hprof文件的同学这时候可能就看到了,执行分析之后,并没有看到内存泄露。

c720ec2b5383

检查内存泄漏神器.png

从上图我们看到SecondeActivity已经是红色,标明被回收了,不存在内存泄漏。

同时,我调试跟踪了一下unsubscribe调用栈,因为是一堆抽象类及接口,又有一堆的实现类,所以,最效率的方法还是调试跟踪,这时候路径就出来了,具体怎么个调发请看我的手稿,比较粗糙。

最终发现,最后的根源就是hander 的 removeCallbacksAndMessages 方法被调用了。

c720ec2b5383

unsubscribe

c720ec2b5383

removeCallbacksAndMessages.png

因此是不存在内存泄漏的,是这样的吗??让我们来在看一个例子!

假如耗时任务本来就是一个异步任务呢?

c720ec2b5383

修改一下

跑几秒钟,然后回到MainActivity,这时候你在GC一下,hprof文件导出看看,我去,泄漏了。

c720ec2b5383

真的泄漏了

在看看控制台,我去,一直执行到跑完。

c720ec2b5383

一直跑完了

然后等跑完了,在GC一下,在导出hprof文件看看,内存泄漏依然还在,SecondActivity永久放入了你的内存,知道APP进程死掉才会释放。

不信的话,可以多启动SecondActivity,退出SecondActivity几次 ,你会发现内存不断飙升~~

c720ec2b5383

内存不断飙升

我继续在思考,是不是这个耗时任务本身就丢在一个线程中执行,所以,如果我们rx不切换线程,是不是就不会泄露呢?

所以,还是不服,在改改代码,继续~

c720ec2b5383

rx不切换线程了,反正是在非主线程做耗时操作

结果,并没有什么卵用,和上述情况一致,多次启动、关闭SecondActivity ,你会发现内存一样会飙升,GC后,导出hprof文件看看,一样泄露了了。

所以,大家应该懂了使用 rx的正确知识,自己的任务都同步写,线程切换交给Rx,因为Rx更懂你~~。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值