Android内存泄露分析
来源:互联网 发布:天启挂机 源码 编辑:程序博客网 时间:2024/06/10 09:49
1 什么是内存泄露
java使用有向图机制,通过GC自动检查内存中的对象,如果GC发现一个或一组对象为不可到的状态,则该对象从内存中回收。也就是说,一个对象不被任何引用指向的时候,则该对象会被GC发现的时候被回收。另外,如果一组对象只包含相互的引用,而没有来自它们之外的外部引用,仍然属于不可达。
Android中内存泄露的原因
1 Android中使用Handler造成的内存泄露
在Android中,我们经常使用Handler来进行异步操作更新主线程UI,通常我们的代码会专业那个实现。
public class MyActivity extends Activity{ Handler handler = new Handler(){ @override public void handleMessage(Message msg){ //pass } };}
Android stadio 提示该段代码有可能会造成内存泄露。代码哪里可能会造成内存泄露呢?
- 1.当一个Android应用启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper的主要工作就是一个一个处理消息队列中的消息对象。在Android中,所有Android框架的事件(比如Activity的生命周期方法调用和按钮点击等)都是放入到消息中,然后加入到Looper要处理的消息队列中,由Looper负责一条一条地进行处理。主线程中的Looper生命周期和当前应用一样长。
- 2.当一个Handler在主线程进行了初始化之后,我们发送一个target为这个Handler的消息到Looper处理的消息队列时,实际上已经发送的消息已经包含了一个Handler实例的引用,只有这样Looper在处理到这条消息时才可以调用Handler#handleMessage(Message)完成消息的正确处理。
- 3.在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用。静态的内部类不会持有外部类的引用。
分析一下上面的代码,当我们执行了Activity的finish方法,被延迟的消息会在被处理之前存在于主线程消息队列中10分钟,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的SampleActivity的引用,所以这导致了SampleActivity无法回收,进行导致SampleActivity持有的很多资源都无法回收,这就是我们常说的内存泄露。
注意上面的new Runnable这里也是匿名内部类实现的,同样也会持有SampleActivity的引用,也会阻止SampleActivity被回收。
要解决这种问题,思路就是不适用非静态内部类,继承Handler时,要么是放在单独的类文件中,要么就是使用静态内部类。因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。当你需要在静态内部类中调用外部的Activity时,我们可以使用弱引用来处理。另外关于同样也需要将Runnable设置为静态的成员属性。注意:一个静态的匿名内部类实例不会持有外部类的引用。 修改后不会导致内存泄露的代码如下
public class SampleActivity extends Activity { /** * Instances of static inner classes do not hold an implicit * reference to their outer class. */ private static class MyHandler extends Handler { private final WeakReference<sampleactivity> mActivity; public MyHandler(SampleActivity activity) { mActivity = new WeakReference<sampleactivity>(activity); } @Override public void handleMessage(Message msg) { SampleActivity activity = mActivity.get(); if (activity != null) { // ... } } } private final MyHandler mHandler = new MyHandler(this); /** * Instances of anonymous classes do not hold an implicit * reference to their outer class when they are static. */ private static final Runnable sRunnable = new Runnable() { @Override public void run() { /* ... */ } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mHandler.postDelayed(sRunnable, 1000 * 60 * 10); // Go back to the previous Activity. finish(); }}
其实在Android中很多的内存泄露都是由于在Activity中使用了非静态内部类导致的,就像本文提到的一样,所以当我们使用时要非静态内部类时要格外注意,如果其实例的持有对象的生命周期大于其外部类对象,那么就有可能导致内存泄露。个人倾向于使用文章的静态类和弱引用的方法解决这种问题。
待继续补充。。。
- Android内存泄露分析
- android内存泄露分析
- Android内存泄露分析
- Android内存泄露分析
- Android 内存泄露分析
- Android 内存泄露 分析
- android内存泄露分析
- Android内存泄露分析
- Android 内存泄露分析
- Android内存泄露分析
- Android内存泄露分析
- Android 内存泄露分析
- android 内存泄露分析
- Android 内存泄露 案例分析
- android内存泄露分析-MAT
- Android内存泄露与分析
- android开发内存泄露分析
- MAT分析Android内存泄露
- OKHttp框架源码分析(一)
- Broadcast广播
- 【不积跬步_无以至千里】 数学知识(不定时整理)
- UVALive-4329-Ping-pong
- 开发线程安全的Servlet
- Android内存泄露分析
- session入redis
- 安卓中浏览器点击图标自动跳转网址
- dp、dpi、pt、sp的关系
- Intellij and github
- 动态代理模式(设计模式10)
- Bridge桥接模式(设计模式11)
- java中Collection 与Collections的区别
- 字符拆分存入Map计算单词的个数