Android内存泄漏场景
首先我们提出一个问题,什么是内存泄漏? 内存泄漏,浅显得来讲就是“没有用的对象无法被回收”
而后我们再提出一个问题,内存泄露会导致什么情况?
一定是内存溢出,而后程序崩溃啊!
区别
相信初学者可能不太清楚内存溢出和内存泄漏的区别。
内存溢出:程序使用的空间大于本来系统给它申请的空间。
内存泄漏:在new了对象之后,没有使用这个对象了,但是又没有被回收,一直占用着内存。
储备知识
要想理解内存泄露的知识,首先我们要清楚以下的知识点
Java的GC(Garbage Collection,垃圾回收)机制。
Java的内存管理机制
介绍可以见 浅谈垃圾回收算法
简单判断
如何判断,只用记住一点:A类实例引用B类实例,而A类实例的生命周期长于B类实例的生命周期。
泄漏场景
在Android开发中,内存泄漏的地方还是挺多的,有时候稍不注意就写出了一个内存泄漏的代码。所以说我们要熟记哪些地方容易发生内存泄漏,在代码Review的情况下很容易检查出来。
单例引起的内存泄漏
单例模式使用的地方非常多,它的生命周期常常伴随着App的一生,所以说也十分容易造成内存泄漏。
例如单例模式中引用Activity的Context,而单例模式的生命周期长于Activity。这里单例模式引用Activity的实例,当Activity被销毁,Activity无法被回收,造成内存泄露。
public class Single { private static Single instance; private Context context; private Single(Context context) { this.context = context; } public static Single getInstance(Context context) { if (instance == null) { instance = new Single(context); } return instance; }}
值得一提的是,假如这里引用的Application的Context,将无任何影响。由于Application的生命周期与单例模式同样长。
集合的内存泄漏
在静态集合里面增加对象,增加完成之后该集合将会一直引用此对象,该对象无法被释放。(不过我们也写不出这样沙雕的代码来!
static List<Object> objectList = new ArrayList<>(); for (int i = 0; i < 10; i++) { Object obj = new Object(); objectList.add(obj); obj = null; }
处理方法:在使用完该集合之后,将集合清空。
匿名内部类以及非静态内部类
特点:匿名类和非静态内部类都持有外部类的引用
匿名内部类
Handler泄漏
匿名内部类引起的内存泄露,最典型的例子就是Handler泄漏。当Handler的消息没有发送完毕,Activity就被销毁了,此时Activity无法被即时回收。
public class MainActivity extends Activity{ @SuppressLint("HandlerLeak") private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { //do something... } }; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}
如何处理Handler泄漏呢?我们用static修饰Handler,这样Hanlder的生命周期就与Activity无关了。假如想引用Activity实例,这里可以用一个弱引用来获取。或者者可以在Activity 的onDestroy() 方法中移除所有的消息
handler.removeCallbacksAndMessages(null);public class MainActivity extends Activity{ private final MyHandler handler = new MyHandler(this); @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } private static class MyHandler extends Handler { private final WeakReference<MainActivity> mActivity; public MyHandler(MainActivity activity) { mActivity = new WeakReference<MainActivity>(activity); } @Override public void handleMessage(Message msg) { MainActivity activity = mActivity.get(); } }}
Thread泄漏
在Activity中new Thread时,假如在子线程做耗时操作,当Activity被销毁后,子线程的工作并未完成,此时会内存泄漏。
public class MainActivity extends Activity{ @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); }}
这里同样可以继承 Thread 实现静态内部类来处理。
static修饰的成员变量
假如成员变量被公告为 static,其生命周期将与整个app进程生命周期一样。
Stream未关闭
在调用了流之后,肯定要记得关闭流。用到流的地方一般都是文件操作,虚拟机无法通过垃圾回收来释放这些资源。
其余泄漏
例如service不记得解除绑定,broadcastReceiver不记得解除订阅,EventBus不记得解除订阅等。
常用的检测内存泄漏的工具
光凭肉眼我们其实只能找出比较显著的内存泄露点,还有许多隐藏得比较深的内存泄露。那么我们如何找到这些点呢?当然是利用工具。
Android Lint:Android Studio提供的代码扫描分析工具
Leakcanary: Square 公司开源的「Android 和 Java 的内存泄漏检测库」
总结
在Android系统中,每个App最多能分配大约只有100-200MB的内存空间,由于内存不够,溢出而引起的程序崩溃还是不在少数。所以说,日常开发中还是要千万注意内存泄露。
【附】相关架构及资料
image
资料领取
点赞+加群免费获取 Android 架构设计③群
加群领取获取往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Android内存泄漏场景