0. 前言  

转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52333954

Android的内存泄漏是Android开发领域永恒的话题,那今天就总结一下常见的内存泄漏吧。也给自己提个醒,在以后的编码过程中多注意这个问题。在Android Studio里可以通过一些分析工具比如MAT来找出潜在的内存泄漏,在Android Device Monitor中对相应进行进行Dump HPROF File,并对这个文件在SDK的platform-tools目录下进行<hprof-conv infilePath outfileName>即可在platform-tools目录下生成使用MAT工具查看的hprof文件。

还有如果不清楚Java里的OOM、以及内存泄漏和内存溢出区别的小伙伴,可以参考我之前写过的Java技术——Java中的内存泄漏

此篇将从静态变量引用Activity、匿名类、内部类、Handler、以及监听器等方面的实例说明内存泄漏的发生原因以及解决方案。


1. 单例模式导致内存泄漏(实质是静态变量引用Activity

如果不了解单例模式的小伙伴可以查看我之前写过的设计模式——单例模式解析。已经对单例模式分析的很清楚了。这里就不多赘述了。

单例由于其静态的特性使得其生命周期跟应用一样长,处理不当极易导致内存泄漏。

public class SingleUtils {
private static SingleUtils mInstance = null;
private Context context;
private SingleUtils (Context context){
this.context = context;
} public static SingleUtils getInstance(Context context){
if(mInstance == null){
mInstance = new SingleUtils (context);
}
return mInstance;
} public Object getObject(){//根据业务逻辑传入参数
//返回业务逻辑结果,这里需要用到context
}
}

如果你看了上面链接文中介绍的单例模式,那么就很容易理解下面单例类中返回实例的代码造成了内存泄漏,我们传入了上下文context(传入上下文是为了实现单例类中的业务逻辑),这个上下文可能是Android应用中的一个Activity界面,当它finish掉的时候,这个单例类的静态对象拥有了这个Activity的引用,静态变量是驻扎在JVM的方法区,静态变量引用的对象是不会被GC回收的,因为它们所引用的对象本身就是GC ROOT。导致该Activty一直驻留在内存中,并发生内存泄漏。

解决方案:

在单例中我们尽可能的引用生命周期较长的对象,将第10行代码修改如下即可。

mInstance = new SingleUtils (context.getApplicationContext());

2. 内部类导致内存泄漏

非静态内部类会持有外部类的引用,如果我们在一个外部类中定义一个静态变量,这个静态变量是引用内部类对象,内部类能够引用外部类的成员这一优势,就是通过持有外部类的引用来实现的,但是这将会导致内存泄漏,因为这相当于间接导致静态引用外部类。

public class MyActivity extends Activity {
//非静态内部类User创建的静态实例mUser
private static InnerClass mInnerClass = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mInnerClass = new InnerClass();
}
class InnerClass{
}
}

解决方案:

(1)在onDestroy方法中调用mInnerClass的判空,若不为空,手动置为null即可。

(2)将内部类定义为静态内部类,使其不能与外部类建立关系。

3.匿名导致内存泄漏

匿名内部类同样会持有一个外部类的引用,因此如果在Activity内定义了一个匿名的AsyncTask对象。如果Activity被销毁之后AsyncTask仍然在执行,那就会组织垃圾回收器回收Activity对象,进而导致内存泄漏,直到执行结束才能回收Activity。

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
//子线程中持有Activity的引用
//子线程在Activity销毁后依然会继续执行,导致该Activity内存泄漏
while (true) ;
}
}.execute();
}

解决方案:

(1)在onDestroy中中断子线程的运行。

(2)由于线程池利于管理,可以使用全局的线程池代替在类中创建子线程。

4.Handler导致内存泄漏

定义一个匿名的Runnable对象会间接地引用定义它的Activity对象,而它会被提交到Handler的MessageQueue中,如果它在Activity销毁时还没有被处理(如下例中延迟时间执行),那就会导致内存泄漏了。

private final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) { }
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); handler.postDelayed(new Runnable() {
@Override
public void run() { /* ... */ }
}, Integer.MAX_VALUE);
}

解决方案:

(1)在onDestroy中清空不必要的Message消息。

(2)可以将Handler放入到静态内部类中(静态内部类不会持有外部类的引用)。如果想要在handler内部去调用所在的外部类Activity,可以在handler内部使用弱引用的方式指向所在Activity,这样不会导致内存泄漏。

5.监听器导致内存泄漏

系统服务可以通过context.getSystemService获取,它们负责执行某些后台任务,或者为硬件访问提供接口。如果 context对象想要在服务内部的事件发生时被通知,那就需要把自己注册到服务的监听器中。然而,这会让服务持有Activity的引用,如果忘记在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开发——常见的内存泄漏以及解决方案(一)的更多相关文章

  1. Android开发——常见的内存泄漏以及解决方案(二)

    )Android2.3以后,SoftReference不再可靠.垃圾回收期更容易回收它,不再是内存不足时才回收软引用.那么缓存机制便失去了意义.Google官方建议使用LruCache作为缓存的集合类 ...

  2. Android开发 |常见的内存泄漏问题及解决办法

    在Android开发中,内存泄漏是比较常见的问题,有过一些Android编程经历的童鞋应该都遇到过,但为什么会出现内存泄漏呢?内存泄漏又有什么影响呢? 在Android程序开发中,当一个对象已经不需要 ...

  3. Android中常见的内存泄漏

    为什么会产生内存泄漏? 当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏. ...

  4. android中常见的内存泄漏和解决的方法

    android中的内存溢出预计大多数人在写代码的时候都出现过,事实上突然认为工作一年和工作三年的差别是什么呢.事实上干的工作或许都一样,产品汪看到的结果也都一样,那差别就是速度和质量了. 写在前面的一 ...

  5. Android性能优化之常见的内存泄漏

    前言 对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我们可以借助LeakCanary.MAT等工具来检 ...

  6. 老李分享:Android性能优化之内存泄漏1

    老李分享:Android性能优化之内存泄漏   前言 对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我 ...

  7. 5个Android开发中比较常见的内存泄漏问题及解决办法

    android中一个对象已经不需要了,但是其他对象还持有他的引用,导致他不能回收,导致这个对象暂存在内存中,这样内存泄漏就出现了.   内存泄漏出现多了,会是应用占用过多的没存,当占用的内存超过了系统 ...

  8. Android开发常见的Activity中内存泄漏及解决办法

    上一篇文章楼主提到由Context引发的内存泄漏,在这一篇文章里,我们来谈谈Android开发中常见的Activity内存泄漏及解决办法.本文将会以“为什么”“怎么解决”的方式来介绍这几种内存泄漏. ...

  9. JavaScript如何工作:内存管理+如何处理4个常见的内存泄漏

    摘要: 作者将自己常用的JavaScript模块分享给大家. 原文:JavaScript如何工作:内存管理+如何处理4个常见的内存泄漏 作者:前端小智 Fundebug经授权转载,版权归原作者所有. ...

随机推荐

  1. VMware 虚拟机安装及部署

    Linux系统安装及网络配置 这篇文章介绍关于Linux系统的安装以及网络配置,关于虚拟机配置中网络的几个模式区别进行详细讲解.学习Linux对于后端开发人员来说是很有必要的,结合实际开发,Linux ...

  2. es6声明对象以及作用域与es5对比

    es6声明变量: let x=1;//声明一个变量 const y=2;//声明一个只读常量,声明时必须赋值,之后值不可修改 es5声明变量: var z=3;//声明一个变量 区别: let不存在变 ...

  3. PL/SQL中模拟EBS上下文

    有时,我们需要查询的表或视图,是具有OU屏蔽的,这时我们就需要模拟EBS中的上下文来实现查询数据. BEGIN fnd_global.apps_initialize(user_id =>1,re ...

  4. https 双向验证

    服务器配置 服务器秘钥   服务器公钥证书  ,客户端公钥证书 客户端配置  客户端秘钥+密码 服务器公钥证书 目前android验证ok,pc浏览器添加客户端秘钥证书  ,访问还是失败,待继续查找资 ...

  5. 微软AI发布会,集齐六大亮点召唤黑科技!

    7月12日,微软合作伙伴大会Inspire在华盛顿特区如火如荼地举行.同一天,在相隔5个时区的伦敦,微软还举办了一场关于人工智能的发布会.这是一场智能技术和情感体验两相交融的科技盛宴,既有黑科技,也有 ...

  6. sql server 搭建发布订阅后,改端口不正常工作的问题

    sql 的发布订阅,想必大家都了解,但一般都是在默认的1433的情况下搭建的,那么1433换成别的端口,发布还能正常工作吗? 在一次客户的真实场景上我就遇到了. 好了,今天不想写太多,简化下, 测试环 ...

  7. matplotlib学习之(四)设置线条颜色、形状

    本文是学习<matplotlib for python developers>的一点笔记plot画图时可以设定线条参数.包括:颜色.线型.标记风格.1)控制颜色颜色之间的对应关系为b--- ...

  8. LeetCode Number of 1 Bits 计算1的个数

    题意: 提供一个无符号32位整型uint32_t变量n,返回其二进制形式的1的个数. 思路: 考察二进制的特性,设有k个1,则复杂度为O(k).考虑将当前的数n和n-1做按位与,就会将n的最后一个1去 ...

  9. 详细讲解:通过phpstudy 设置站点域名、站点域名管理

    我们在本地编程的时候,会遇到路径特别长的情况,这样子我们在url中的输入就会变得不方便而且容易报错,那么在phpstudy这个环境中,有一个很好的功能,就是“站点域名管理”,他能让我们的url网址大大 ...

  10. vs2010 opencv2.4.10 配置过程出现的问题 & mfc打开图片

    配置参考网址: http://blog.csdn.net/zy122121cs/article/details/49180541 无法启动程序,系统找不到指定的文件:原因是程序编译有错误(不是路径之类 ...