Android性能优化——之防止内存泄露

又是好久没有写博客了,一直都比较忙,最近终于有时间沉淀和整理一下最近学到和解决的一些问题。

最近进行技术支持的时候,遇到了几个崩溃的问题,都是OOM异常,一般OOM异常给人的感觉应该是加载大图片造成的,但是经过看界面布局,并且分析加载图片的大小发现加载图片方面已经没有什么可以优化的了,但是依然崩溃,没办法了,又用的IDEA工具中的内存监视器,来判断到底是哪里造成内存激增,做哪些操作造成页面资源没有及时释放。最后发现原来是每次关闭这个界面,都没有及时的释放资源,每次开启,都会重新申请资源,造成内存泄露问题。下面我就说一下我们写代码的时候,那些地方容易会造成内存泄露。

首先是在Activity中声明静态变量或者静态方法或者静态控件

静态变量或者方法是放在静态数据区的,也就是在程序运行的过程中,只要加载过这个类之后,静态的变量或者方法,就一直会在静态数据区存在,不会释放资源。因为静态变量或者方法不是凭空存在的,所以需要Activity作为支撑,也就是说这个变量不仅占用了变量本身所存放数据的内存,还占据了这个Activity所占的内存。也就是这个Activity即使被用户关闭了,但是资源并没有被释放。

其次,一些读取数据库动态注册广播没有及时关闭注销也是容易造成内存泄露的

例如例如BroadcastReceiver、ContentObserver,FileObserver在Activity的onDeatory或者某类的生命周期结束后,一定要unregister掉,否则这个Activity会一直被system强引用,不会被内存回收。

单例模式导致的内存泄露,

单例模式的特点就是他的生命周期和Application一样,如果某个Activity示例被一个单利所持有,也就是说单利里面引用了他,就会造成Activity对象会无法正常回收释放。

注:这里的原理和第一种是一样的,都是因为静态变量引用Activity对象,造成Activity无法正常释放资源造成的。

属性动画导致内存泄露

例如代码中设置了属性动画(ObjectAnimator),在Activity中启动了动画,但是在销毁的时候,没有调用cancle方法,虽然我们看不到动画了,但是这个动画依然会不断地播放下去,动画引用所在的控件,所在的控件引用Activity,这就造成Activity无法正常释放。

Handler内部类造成内存泄露

当使用内部类(包括匿名内部类)来创建Handler的时候,Handler对象会隐式的持有一个外部类对象(通常是Activity)的引用,而handler通常会伴随这一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕之后,通过消息机制,通知Handler然后Handler见图片更新到界面,如果用户在网络请求中关闭了Activity,正常情况下,Activity不再被使用,因该会被Gc回收掉,但是,由于该线程未执行完,而该线程持有的Handler的引用,就导致Activity无法被回收(直到网络请求结束),如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。可以在Activity结束后,关闭线程,如果你的Handler是被delay的Message持有了引用,那么调用void removeCallbacksAndMessages(null)方法来移除消息队列。

Android性能优化——之防止内存泄露的相关教程结束。

相关推荐:

怎么优化Python中的字符串拼接操作以避免频繁的内存分配?

+拼接在循环中特别慢,因字符串不可变,每次s=s+item都新建对象并复制全部内容,时间复杂度达O(n²),引发大量内存分配与垃圾回收;推荐用list.append()+''.join()降至O(n)。 为什么+拼接字符串在循环里特别慢? Python中的字符串是不可变对象,每次用+拼接都会创建新字...

如何在Python中通过解包赋值优化变量交换与赋值的执行速度?

Python解包赋值不提升执行速度,其核心价值在于增强可读性、安全性和语义清晰度;它通过结构断言避免手动索引错误,适用于多值返回、可变长解包及字典传参等场景。 Python中的解包赋值本身不会提升变量交换或赋值的“执行速度”,它和传统赋值在底层开销几乎一致;真正带来收益的是代码可读性、安全性与表达意...

如何解决Python多进程共享大字典时的内存拷贝问题?

直接用dict传给子进程会导致内存翻倍,因fork后的写时复制被Python内部操作(如引用计数、哈希查找)意外触发;共享只读字典应使用shared_memory+序列化,配合显式清理。 直接用dict传给子进程,内存几乎必然翻倍——不是因为你要改它,而是Python解释器自己就在偷偷写它。 为什么...