内存泄漏以优化大全

protected void onDestroy() {

super.onDestroy();

mHandler.removeCallbacksAndMessages(null);

}

Thread、AsyncTask

非静态内部类造成内存泄漏还有一种情况就是使用 Thread 或者 AsyncTask。 比如在 Activity 中直接 new 一个子线程 Thread:

public class ThreadActivity extends AppCompatActivity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_thread);

new Thread(new Runnable() {

@Override

public void run() {

//Something

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}).start();

}

}

或者直接新建 AsyncTask 异步任务:

public class AsyncTaskActivity extends AppCompatActivity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_async);

new AsyncTask<Void, Void, Void>() {

@Override

protected Void doInBackground(Void… voids) {

//something

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

return null;

}

}.execute();

}

}

很多初学者都会像上面这样新建线程和异步任务,殊不知这样的写法非常不友好,这样方式新建的子线程 Thread 和 AsyncTask 都是匿名内部类对象,默认就隐式的持有外部 Activity 的引用,导致 Activity 内存泄漏。要避免内存泄漏的话还是需要像上面 Handler 一样使用静态内部类 + 弱引用的方式。

未取消注册或回调导致内存泄漏


比如我们在 Activity 中注册广播,如果在 Activity 销毁后不取消注册,那么这个广播会一直存在系统中,同上面所说的非静态内部类一样持有 Activity 引用,导致内存泄漏。因此注册广播后在 Activity 销毁后一定要取消注册。

public class BroadcastActivity extends AppCompatActivity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_broadcast);

registerReceiver(mReceiver, new IntentFilter());

}

private BroadcastReceiver mReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

//接收到广播需要做的逻辑

}

};

@Override

protected void onDestroy() {

super.onDestroy();

unregisterReceiver(mReceiver);

}

}

在注册观察者模式的时候,如果不及时取消也会造成内存泄漏。比如使用 Retrofit + RxJava 注册网络请求的观察者回调,同样作为匿名内部类持有外部引用,所以需要记得在不用或者销毁的时候取消注册。

Timer 和 TimerTask 导致内存泄漏


Timer 和 TimerTask 在 Android 中通常会被用来做一些计时或循环任务,比如实现无限轮播的 ViewPager:

public class TimerActivity extends AppCompatActivity {

private ViewPager mViewPager;

private PagerAdapter mAdapter;

private Timer mTimer;

private TimerTask mTimerTask;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_timer);

init();

mTimer.schedule(mTimerTask, 3000, 3000);

}

private void init() {

mViewPager = findViewById(R.id.view_pager);

mAdapter = new ViewPagerAdapter();

mViewPager.setAdapter(mAdapter);

mTimer = new Timer();

mTimerTask = new TimerTask() {

@Override

public void run() {

runOnUiThread(new Runnable() {

@Override

public void run() {

loopViewpager();

}

});

}

};

}

private void loopViewpager() {

if (mAdapter.getCount() > 0) {

int curPos = mViewPager.getCurrentItem();

curPos = (++curPos) % mAdapter.getCount();

mViewPager.setCurrentItem(curPos);

}

}

private void stopLoopViewPager() {

if (mTimer != null) {

mTimer.cancel();

mTimer.purge();

mTimer = null;

}

if (mTimerTask != null) {

mTimerTask.cancel();

mTimerTask = null;

}

}

@Override

protected void onDestroy() {

super.onDestroy();

stopLoopViewPager();

}

}

当我们 Activity 销毁时,有可能 Timer 还在继续等待执行 TimerTask,它持有 Activity 的引用不能被回收,因此当我们 Activity 销毁的时候要立即 cancel 掉 Timer 和 TimerTask,以避免发生内存泄漏。

集合中的对象未清理造成内存泄漏


这个比较好理解,如果一个对象放入到 ArrayList、HashMap 等集合中,这个集合就会持有该对象的引用,当我们不再需要这个对象时,也并没有将它从集合中移除,这样只要集合还在使用(而此对象已经无用了),这个对象就造成了内存泄漏。并且如果集合被静态引用的话,集合里面那些没有用的对象更会造成内存泄漏了,所以在使用集合时要及时将不用的对象从集合 remove,或者 clear 集合,以避免内存泄漏。

资源未关闭或释放导致内存泄漏


在使用 IO、File 流或者 Sqlite、Cursor 等资源时要及时关闭。这些资源在进行写操作时通过都使用了缓冲,如果及时不关闭,这些缓冲对象就会一直被占用而得不到释放,以至于发生内存泄漏。因此我们在不需要使用它们的时候就及时关闭,以便缓冲能及时得到释放,从而避免内存泄漏。

属性动画造成内存泄漏


动画同样是一个耗时任务,比如在 Activity 中启动了属性动画(ObjectAnimator),但是在销毁的时候没有调用 cancel 方法,虽然我们看不到动画了,但是这个动画依然会不断地播放下去,动画引用所在的控件,所在的控件引用 Activity ,这就造成 Activity 无法正常释放。因此同样要在 Activity 销毁的时候 cancel 掉属性动画,避免发生内存泄漏。

@Override

protected void onDestroy() {

super.onDestroy();

mAnimator.cancel();

}

WebView 造成内存泄漏


关于 WebView 的内存泄漏,因为 WebView 在加载网页后会长期占用内存而不能被释放,因此我们在 Activity 销毁后要调用它的 destroy() 方法来销毁它以释放内存。 另外在查阅 WebView 内存泄漏相关资料时看到这种情况: WebView 下面的 Callback 持有 Activity 引用,造成 WebView 内存无法释放,即使是调用了 WebView.destroy() 等方法都无法解决问题(Android 5.1 之后)。 最终的解决方案是:在销毁 WebView 之前需要先将 WebView 从父容器中移除,然后在销毁 WebView。 详细分析过程可以参考这篇文章:WebView 内存泄漏解决方法

@Override

protected void onDestroy() {

super.onDestroy();

if (mWebView != null) {

((ViewGroup) mWebView.getParent()).removeView(mWebView); //先从父控件中移除 WebView.

mWebView.stopLoading();

mWebView.getSettings().setJavaScriptEnabled(false);

mWebView.clearHistory();

mWebView.removeAllViews();

mWebView.destroy();

mWebView = null;

}

}

总结


内存泄漏在 Android 内存优化是一个比较重要的一个方面,很多时候程序中发生了内存泄漏我们不一定就能注意到,所有在编码的过程中养成良好的习惯。总结下来只要做到以下这几点就能避免大多数情况的内存泄漏:

  • 构造单例的时候尽量别用 Activity 的引用

  • 静态引用是注意引用对象的置空或者少用静态引用

  • 使用静态内部类 + 弱引用代替非静态内部类

  • 及时取消广播或者观察者注册

  • 耗时任务、属性动画在 Activity 销毁时记得 cancel

  • 文件流、Cursor 等资源及时关闭

  • Activity 销毁时 WebView 的移除和销毁

最后


小编在网上收集了一些 Android 开发相关的学习文档、面试题、Android 核心笔记等等文档,希望能帮助到大家学习提升,如有需要参考的可以直接去我 codechina地址:https://codechina.csdn.net/u012165769/Android-T3 访问查阅。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

架构师筑基包括哪些内容

我花了将近半个月时间将:深入 Java 泛型.、注解深入浅出、并发编程.、数据传输与序列化、Java 虚拟机原理、反射与类加载、高效 IO、Kotlin项目实战等等Android架构师筑基必备技能整合成了一套系统知识笔记PDF,相信看完这份文档,你将会对这些Android架构师筑基必备技能有着更深入、更系统的理解。

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容

注:资料与上面思维导图一起看会更容易学习哦!每个点每个细节分支,都有对应的目录内容与知识点!



这份资料就包含了所有Android初级架构师所需的所有知识!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

架构师筑基包括哪些内容

我花了将近半个月时间将:深入 Java 泛型.、注解深入浅出、并发编程.、数据传输与序列化、Java 虚拟机原理、反射与类加载、高效 IO、Kotlin项目实战等等Android架构师筑基必备技能整合成了一套系统知识笔记PDF,相信看完这份文档,你将会对这些Android架构师筑基必备技能有着更深入、更系统的理解。

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容

注:资料与上面思维导图一起看会更容易学习哦!每个点每个细节分支,都有对应的目录内容与知识点!

[外链图片转存中…(img-v5588ZpE-1711942687477)]
[外链图片转存中…(img-t3gzBjoT-1711942687477)]
这份资料就包含了所有Android初级架构师所需的所有知识!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值