Update 性能优化口水话.md

master
Omooo 4 years ago
parent b6c9ec728f
commit 527409e1f6
  1. 2
      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。 在做积分商城时,有一个编辑地址页面,里面有三个 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 的使用不当等。 除此之外,对于内存泄露还有一些经验之谈,比如 Handler 的使用不当可能导致的内存泄露,解决办法就是静态内部类 + 弱引用,还有及时关闭资源文件、Context 的使用不当等。

Loading…
Cancel
Save