写点什么

[译] 内存泄露的八种花样 (1),音视频开发工程师前景

用户头像
Android架构
关注
发布于: 20 分钟前

不幸的是,由于内部类可以直接访问到它的外部类的变量,这个特性意味着内部类会隐式的持有一个对它的外部类的引用,这间接导致了我们不小心又泄露了 Activity。

4. 匿名类

同样的,匿名类也持有一个指向它申明的地方所在的类的引用。如果你在[Activity 内定义和实例化一个 Asyn


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


cTask 匿名类](


),那也可能发生内存泄露


void startAsyncTask() {new AsyncTask<Void, Void, Void>() {@Override protected Void doInBackground(Void... params) {while(true);}}.execute();}


super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);View aicButton = findViewById(R.id.at_button);aicButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {startAsyncTask();nextActivity();}});



AsyncTask 的内存泄露

5. Handler

同样的原则也适用于后台任务:[定义一个匿名的 Runnable,然后将它加入 Handler 的处理队列里](


)。这个 Runnable 对象会隐含的持有一个指向它定义的时候所在的 Activity 的引用,然后它会作为一个消息对象加入到 Handler 的消息队列里去。在 Activity 生命周期结束之后,只要这个消息还没被 Activity 处理,那就有一条引用链指向我们的 Activity 对象,使得 Activity 对象无法被回收,进而泄露。


void createHandler() {new Handler() {@Override public void handleMessage(Message message) {super.handleMessage(message);}}.postDelayed(new Runnable() {@Override public void run() {while(true);}}, Long.MAX_VALUE >> 1);}


View hButton = findViewById(R.id.h_button);hButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {createHandler();nextActivity();}});



Handler 导致的内存泄露

6. 线程

类似的问题我们可以在[线程](


)、[定时任务(TimerTask)](


)里发现。


void spawnThread() {new Thread() {@Override public void run() {while(true);}}.start();}


View tButton = findViewById(R.id.t_button);tButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {spawnThread();nextActivity();}});



线程使用不当导致内存泄露

7. 定时任务

只要它们是通过匿名类的方式定义和实例化的,即便是工作在另外的线程,依旧会在 Activity 被 destroy 之后,存在一条指向 Activity 的引用链,导致 Activity 泄露。


void scheduleTimer() {new Timer().schedule(new TimerTask() {@Overridepublic void run() {while(true);}}, Long.MAX_VALUE >> 1);}


View ttButton = findViewById(R.id.tt_button);ttButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {scheduleTimer();nextActivity();}});



TimerTask 导致的内存泄露

8. 系统服务

最后,还有一些系统服务可以通过上下文 Context 对象上的[getSystemService](


))方法获取到。这些服务运行在他们各自的进程里,协助应用执行某种类型的的后台任务,或者和设备的硬件进行交互。如果 Context 对象需要系统服务内的某个事件发生的时候通知到这个 Context,那么它需要把自身作为一个[监听器](


)注册给系统服务。系统服务也由此持有了一个对 Activity 对象的应用。如果我们在 Activity 的生命周期结束的时候忘了去反注册这个监听器,就会发生泄露。


void registerListener() {SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);}View smButton = findViewById(R.id.sm_button);smButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {registerListener();nextActivity();}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
[译]内存泄露的八种花样(1),音视频开发工程师前景