写点什么

一个优秀程序员不可避免的问题:内存泄漏,ffmpeg 音视频开发实战 6 下载

用户头像
Android架构
关注
发布于: 2021 年 11 月 05 日

有了上图,理解内存泄漏的概念就很简单,说白了就是:长生命周期对象 A 持有了短生命周期的对象 B,那么只要 A 不脱离 GC Root 的链,那么 B 对象永远没有可能被回收,因此 B 就泄漏了。

有什么危害?

危害的话,如开篇所说。如果泄漏的内存很小,几字节,几 kb….对于现在的机器性能,就像星爵打灭霸…“伤害”基本无视。但是如果泄漏的足够多,普通的 GC 无法回收这些泄漏的内存,那么堆将持续增加,当堆足够大的时候,就会触发“stop-the-world” GC,直接在主线程进行耗时的 GC。


主线程进行耗时操作,每一个 android 开发者都明白这意味着什么….


所以内存泄漏足够严重,其危害还是很严重的。

二、实践

对于我们日常开发来说,有比较多的场景稍不注意就会存在内存泄漏的风险。让我们一起留意一下:

2.1、内部类 Inner classes

内部类存在内存泄漏的风险,是一个老生常谈的话题。说白了就是因为我们在 new 一个内部类时,编译器会在编译时让这个内部类的实例持有外部对象。


这也就是,为啥我们的内部类可以引用到外部类变量、方法的原因。


上段代码:


public class BadActivity extends Activity {


private TextView mMessageView;


@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.layout_bad_activity);mMessageView = (TextView) findViewById(R.id.messageView);


new LongRunningTask().execute();}


private class LongRunningTask extends AsyncTask<Void, Void, String> {


@Overrideprotected String


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


doInBackground(Void... params) {return "Am finally done!";}


@Overrideprotected void onPostExecute(String result) {mMessageView.setText(result);}}}


大家应该都能看出这里的问题吧。作为非静态内部类的LongRunningTask,会持有BadActivity。并且LongRunningTask是一个长时间任务,也就是说,在这个任务没有完成时,BadActivity是不会被回收的,因此我们的BadActivity就被泄漏了。那么怎么改呢?

解决原理

首先我不能让LongRunningTask持有BadActivity。那么我们需要使用静态内部类(static class)。这样的确不会持有BadActivity,但是问题来了,我们LongRunningTask不持有BadActivity,也就意味着没办法引用到BadActivity中的变量,那么我们的更新 UI 的操作就做不了,也就是说还是要显示的传一个BadActivity中我们需要的变量进来…但是这样有造成了同样的泄漏问题。


因此,我们需要对传入的变量使用WeakReference进行包一层。但发生 GC 的时候,告诉 GC 收集器“我”可以被回收。


上改造后的代码:


public class GoodActivity extends Activity {


private AsyncTask mLongRunningTask;private TextView mMessageView;


@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.layout_good_activity);mMessageView = (TextView) findViewById(R.id.messageView);


mLongRunningTask = new LongRunningTask(mMessageView).execute();}


@Overrideprotected void onDestroy() {super.onDestroy();mLongRunningTask.cancel(true);}


private static class LongRunningTask extends AsyncTask<Void, Void, String> {


private final WeakReference<TextView> messageViewReference;


public LongRunningTask(TextView messageView) {this.messageViewReference = new WeakReference<>(messageView);}


@Overrideprotected String doInBackground(Void... params) {String message = null;if (!isCancelled()) {message = "I am finally done!";}return message;}


@Overrideprotected void onPostExecute(String result) {TextView view = messageViewReference.get();if (view != null) {view.setText(result);}}}}

2.2、匿名类 Anonymous classes

这一类和 2.1 很类似。本质都是持有外部对象的引用。


上一段很常见的代码:


public class MoviesActivity extends Activity {


private TextView mNoOfMoviesThisWeek;


@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.layout_movies_activity);

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
一个优秀程序员不可避免的问题:内存泄漏,ffmpeg音视频开发实战6下载