什么是内存泄漏:

内存泄漏是当程序不再使用到的内存时,释放内存失败而产生了无用的内存消耗。内存泄漏并不是指物理上的内存消失,这里的内存泄漏是值由程序分配的内存但是由于程序逻辑错误而导致程序失去了对该内存的控制,使得内存浪费。
Java会使用有向图的方法进行管理内存,实时监控对象是否可以达到,如果不可到达,则就将其回收,这样也可以消除引用循环的问题。

上图中的绿色部分,即是内存可以回收的部分。


内存泄漏分类一:activity关闭时资源无法回收

(activity内的变量生命周期超越了Activity,对象被生命周期长的对象引用,activity被静态集合引用导致activity不能释放)activity关闭时资源无法回收(activity内的变量生命周期超越了Activity,对象被生命周期长的对象引用,activity被静态集合引用导致activity不能释放)


1.单例造成的内存泄漏(Application和Activity的context生命周期问题)

举例

 public class AppManager {private static AppManager instance;private Context context;private AppManager(Context context) {this.context = context;}public static AppManager getInstance(Context context) {//此处修改了原文代码,请留意if (instance == null) {instance = new AppManager(context);}return instance;}
}

分析
这是一个普通的单例模式,当创建这个单例的时候,由于需要传入一个Context,所以这个Context的生命周期的长短至关重要:
case1 传入的是Application的Context:这将没有任何问题,因为单例的生命周期和Application的一样长 ;
case2 传入的是Activity的Context:当这个Context所对应的Activity退出时,由于该Context和Activity的生命周期一样长(Activity间接继承于Context),所以当前Activity退出时它的内存应该需要被回收,但是又因为(生命周期和Application一样长的)单例对象持有该Activity的引用导致Activity无法回收。
关于Application的context与Activity的context的使用,请见鸿神的博客

如果采用上面的方式,在Activity1中这样使用:

AppManager.getInstance(this);

就会有问题,应该这样使用

AppManager.getInstance(this.getApplicationContext());

然而,好的程序不应该让调用者来决定究竟应该用什么参数。因此最好的修改是如下:
解决

public class AppManager {private static AppManager instance;private Context context;private AppManager(Context context) {this.context = context.getApplicationContext();}public static AppManager getInstance(Context context) {if (instance != null) {instance = new AppManager(context);}return instance;}
}

2.使用静态的Android控件

举例

public class Static_Leak extends AppCompatActivity {static TextView view;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_static__leak);view = (TextView) findViewById(R.id.text);}
}

分析
static变量在内存中是单独存在于内存块中的,控件(上面的例子的问题中指的是TextView )是持有Activity的引用的,这种情况下,Activity是没法被彻底销毁的,因为在内存中一直有一个引用(TextView 指向Activity),导致Activity也无法被回收,自然就会内存泄漏了
解决
方法1.不用static修饰
方法2.使用完回收,将View 指向Activity的引用去除
方法2的例子:

public class Static_Leak extends AppCompatActivity {static TextView view;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_static__leak);view = (TextView) findViewById(R.id.text);}@Overrideprotected void onDestroy() {super.onDestroy();view = null;}
}

下面的三种情况都是非静态内部类导致的内存泄漏(都是非静态内部类引用了Activity导致Activity无法回收)

3.非静态内部类创建静态实例造成的内存泄漏(非静态内部类引发的血案)

举例

public class Static_Inner_leak extends AppCompatActivity {static Demo sInstance = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_static__inner_leak);if (sInstance == null) {sInstance = new Demo();}}class Demo {void doSomething() {}}
}

分析
这样就在Activity内部创建了一个非静态内部类的单例,每次启动Activity时都会使用该单例的数据,这样虽然避免了资源的重复创建,不过这种写法却会造成内存泄漏。因为非静态内部类默认会持有外部类的引用,而又使用了该非静态内部类创建了一个静态的实例,该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。

关于非静态内部类默认会持有外部类的引用,请看这里。
解决
正确的做法为:
将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例,如果需要使用Context,请使用ApplicationContext(原因见单例的内存泄漏) 。


4.线程造成的内存泄漏(非静态内部类引发的血案)

举例

public class Thread_leak extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_thrad_leak);new AsyncTask<Void,Void,Void>(){@Overrideprotected Void doInBackground(Void... params) {SystemClock.sleep(10000);return null;}};new Thread(new Runnable() {@Overridepublic void run() {SystemClock.sleep(10000);}}).start();}
}

分析
上面的异步任务和Runnable都是一个匿名内部类,因此它们对当前Activity都有一个隐式引用。如果Activity在销毁之前,任务还未完成, 那么将导致Activity的内存资源无法回收,造成内存泄漏。
解决

public class Thread_leak extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_thrad_leak);new Thread(new MyRunnable()).start();new MyAsyncTask(this).execute();}static class MyAsyncTask extends AsyncTask<Void, Void, Void> {private WeakReference<Context> weakReference;public MyAsyncTask(Context context) {weakReference = new WeakReference<>(context);}@Overrideprotected Void doInBackground(Void... params) {SystemClock.sleep(10000);return null;}@Overrideprotected void onPostExecute(Void aVoid) {super.onPostExecute(aVoid);MainActivity activity = (MainActivity) weakReference.get();if (activity != null) {}}}static class MyRunnable implements Runnable{@Overridepublic void run() {SystemClock.sleep(10000);}}
}

5.Handler造成的内存泄漏(非静态内部类引发的血案)

参见我的上一篇博客。


可见,三个非静态内部导致的内存泄漏的例子,解决方案都是改成静态内部类,让这个类不依赖Activity的生命周期(如果需要还要使用弱引用,还有注意Application和Activity的context的生命周期)。


内存泄漏分类二:没有回收,释放,解绑,清理等等

  1. 资源对象没关闭造成的内存泄露
    ( 例如对于使用了,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭,否则这些资源将不会被回收,造成内存泄漏。)
  2. 没释放资源造成的内存泄露
  3. 注册某个对象后未反注册(例如 广播BraodcastReceiver,注册了一些ContentObserver,需要注销)
  4. 集合中对象没清理造成的内存泄漏(和上面的分类一,第二种的解决方案类似)

参考链接:
http://www.maiziedu.com/article/9126/
http://blog.csdn.net/cyq1028/article/details/19980369

Android 内存泄漏分析(完)相关推荐

  1. android释放acitity内存,Android 内存泄漏分析与解决方法

    在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...

  2. Android内存泄漏分析及调试

    2019独角兽企业重金招聘Python工程师标准>>> Android内存泄漏分析及调试 分类: Android2013-10-25 11:31 5290人阅读 评论(5) 收藏 举 ...

  3. Android 内存泄漏分析指北

    android 内存泄漏分析指北 简单来说内存泄漏就是当对象不再被应用程序使用,但是垃圾回收器却不能移除它们,因为它们正在被引用 java 垃圾回收介绍: Java 虚拟机运行所管理的内存包括以下几个 ...

  4. Android 内存泄漏分析与解决方法

    Android 内存泄漏分析与解决方法 参考文章: (1)Android 内存泄漏分析与解决方法 (2)https://www.cnblogs.com/start1225/p/6903419.html ...

  5. Android内存泄漏分析

    内存泄漏指的是程序中不再使用的对象对象由于某些原因无法被正常GC回收.对象没 有及时释放,就会占据宝贵的内存空间,因而导致后续分配内存的时候,内存空间不足出现OOM.如果无用对象占据的控件越大,那么可 ...

  6. android 内存泄漏分析工具,Android内存泄漏终极解决篇(上)

    一.概述 在Android的开发中,经常听到"内存泄漏"这个词."内存泄漏"就是一个对象已经不需要再使用了,但是因为其它的对象持有该对象的引用,导致它的内存不能 ...

  7. Mac Android 内存泄漏分析 实战演练

    虚的概念就不讲了,自己去网上搜,一大堆.  这里来一次真刀真枪的实操实战演练. 简书上有一篇讲解 内存泄漏分析 的文章,总结的很到位,由浅入深,比较全面.建议结合起来阅读 内存泄露实例分析 -- An ...

  8. Android内存泄漏分析及检测工具LeakCanary简介,androidui库

    Android内存优化是APP稳定运行的重要一环,开发过程中如果代码写的过于随意,很容易造成内存泄漏,多次累积之后,便会产生OOM,进而造成app崩溃.本文介绍了内存泄漏的相关知识和检测工具LeakC ...

  9. android定时器内存泄露,Android内存泄漏分析以及解决方案

    本文是看了公众号的文章,非常感谢,链接如下 概念 1.什么是内存泄漏? 一句话总结的话,那就是生命周期长的对象持有短生命周期的对象的引用导致其无法被及时释放,就会造成内存泄漏.(内存泄漏最终会导致内存 ...

最新文章

  1. 写了个Python脚本监控nginx进程
  2. 18.了解各种与排序有关的选择
  3. creo减速器建模实例_3.16减速器箱体附件建模
  4. tinkerpop mysql_图论数据库未来的发展方向?
  5. Python程序员都会喜欢的6个库
  6. 法学类计算机专业,就业蓝皮书:计算机类专业领跑薪酬榜 法学专业被亮“红牌”...
  7. 【渝粤教育】国家开放大学2018年春季 0222-21T模拟电子电路 参考试题
  8. JavaScript基础1
  9. 基于cpolar内网穿透工具ssh远程访问linux服务器
  10. PowerShell 开启无线热点
  11. Nexus 5刷阿里云OS
  12. CAS号:2417213-21-7以(ZPS-PVPA)为催化剂载体
  13. Error:Initialization error (angular 2 language service). Cannot read property 'CommandTypes' of unde
  14. 对于Ubuntu16.04中jstest-gtk不能正常识别Logitech G920 racing wheel的问题补充
  15. 最全的硬盘修复专题帖1(转贴)
  16. 试戴耳钉会感染艾滋病吗?
  17. 荷露叮咚wp建站系列视频课程.3WordPress功能菜单介绍
  18. DC888 : 数据流分析
  19. 摩拜ofo均取消月卡优惠;陌陌7.35亿美元收购探探;京东腾讯入股步步高丨价值早报
  20. 后 R-CNN时代, Faster R-CNN、SSD、YOLO 各类变体统治下的目标检测综述:Faster R-CNN系列胜了吗?,(知乎ChenJoya大佬,讲的挺好的,记录一下)

热门文章

  1. echart的关系图高亮_Echarts 环形图 默认高亮展示某个数据
  2. 码风改变计划(暂定)
  3. c++ 初始化列表和构造函数初始化区别
  4. Java开源爬虫框架crawler4j
  5. python学习之路-day8
  6. jdk5.0的新特性
  7. phpunit+selenium环境搭建
  8. C语言通过网络实现发送文件的一点记录
  9. 动态规划基础——爬楼梯(Leetcode 70)
  10. android 属性动画还原,属性动画和补间动画