From 527409e1f6bb2cda41be5447a2ec1b2fa10c5fa5 Mon Sep 17 00:00:00 2001 From: Omooo <869759698@qq.com> Date: Wed, 5 Aug 2020 07:35:10 +0800 Subject: [PATCH] =?UTF-8?q?Update=20=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=8F=A3=E6=B0=B4=E8=AF=9D.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blogs/Android/口水话/性能优化口水话.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blogs/Android/口水话/性能优化口水话.md b/blogs/Android/口水话/性能优化口水话.md index f1557dc..b9af5b4 100644 --- a/blogs/Android/口水话/性能优化口水话.md +++ b/blogs/Android/口水话/性能优化口水话.md @@ -44,7 +44,7 @@ Apk 包主要分为几个部分,libs so 库、dex、res、assets、resources.a 在做积分商城时,有一个编辑地址页面,里面有三个 EditText 并设置了 TextChangedListener,在跑 Profiler 时发现页面已经退出了但是还存在三个该 Activity 的应用,并且都定位到了 TextWatcher 那一行,然后我试了强制 gc 再退回桌面还是存在,说明是内存泄露了。但是大家一直都这么写,并没有在 onDestory 时去移除 Listener 呀。我的测试机是三星 7,然后我试了一下我的小米 9,发现就没问题了。初步怀疑是系统 bug,然后我用 Google 的模拟器,实际测试一下 Android 8 以上没有问题,以下就存在内存泄露。但是项目中很多这样的,解决办法就是可以在 BaseActivity 的 onDestory 去遍历 View 树清空 Listener。 -我在 review 代码时还遇到同事写的一个动画相关的内存泄露,一个静态方法,参数是一个 View,里面用一个静态的 ObjectAnimator 去对这个 View 进行动画处理,然后 LeakCanary 就检测出来内存泄露了。他的做法就是把静态方法改为实例方法就解决了。但是他以为是静态的 ObjectAnimator 持有了 View 的引用导致 Activity 不能被回收,其实呢 ObjectAnimator 在内部持有的是 View 的弱引用,所以事实上并不是这个原因。到底原因是在哪呢?其实是在他给这个 ObjectAnimator 设置了 Listener 然在 Listener 对 View 进行了相关操作,这就形成了一个强引用链 ObjectAnimator -> ArrayList -> View,最终导致了 Activity 未被销毁。所以之前写的静态方法也是可以的,只是需要在 Activity onDestory 时去 removeAllListeners 即可。 +我在 review 代码时还遇到同事写的一个动画相关的内存泄露,一个静态方法,参数是一个 View,里面用一个静态的 ObjectAnimator 去对这个 View 进行动画处理,然后 LeakCanary 就检测出来内存泄露了。他的做法就是把静态方法改为实例方法就解决了。但是他以为是静态的 ObjectAnimator 持有了 View 的引用导致 Activity 不能被回收,其实呢 ObjectAnimator 在内部持有的是 View 的弱引用,所以事实上并不是这个原因。到底原因是在哪呢?其实是在他给这个 ObjectAnimator 设置了 Listener,然后在 Listener 对 View 进行了相关操作,这就形成了一个强引用链 ObjectAnimator -> ArrayList -> View,因为 ObjectAnimator 是静态的,所以最终导致了 Activity 未被销毁。所以之前写的静态方法也是可以的,只是需要在 Activity onDestory 时去 removeAllListeners 即可。一般情况下,我们写的都是 ObjectAnimator 的实例,并且并没有在 onDestory 时去 cancle、removeAllListeners,这样会不会有问题呢?其实并没有什么太大的问题,也不会导致内存泄露。在动画执行完成后,并且在下一次 gc 到来时,对象还是会被回收的。如果动画的执行时间比较长,导致动画还持有 Activity 的引用以至于 Activity 未被及时回收,这是有问题的。但是一般动画执行时间比较短,再加上 gc 时机不确定,所以这时没有 cancle removeAllListeners 也是可以忽略的,加上其实也有好处,提前回收罢了,避免占有系统资源。 除此之外,对于内存泄露还有一些经验之谈,比如 Handler 的使用不当可能导致的内存泄露,解决办法就是静态内部类 + 弱引用,还有及时关闭资源文件、Context 的使用不当等。