Android 中常见内存泄露的几种情况

原文连接 Android 中常见内存泄露的几种情况

我们在开发Android应用时,有时候会遇到程序因占用内存过高而造成的oom(out of memory),而本质的原因就是开发过程中内存使用的不合理以及应用中存在的内存泄露。

我们知道Java代码本身有自己的垃圾回收机制,所以在开发的过程中我们无需特意管理内存的分配,但是它仍旧有内存泄露的风险。我们如果引用了一个已经不再使用的对象,那么java代码的垃圾回收器就会因为一直持有引用而造成内存无法被回收。纵然短期内泄露的内存不多,但是在长期的使用过程中由于内存泄露的不断发生,最终程序就会因为内存泄露而产生oom。

这里引用一张C++/ Java的内存泄露图

oom1

在c++与java还有一些主流的编程语言当中,都是通过上图中的对象可达性分析来判断对象是否存活的。基本的思路是通过GC Root 作为对象的起点,在起点这里对所有对象向下进行搜索,如果一个对象没有任何引用链连接时,那么这个对象可视为不可用,因此就会回收这个对象。

java 和 c++ 对内存管理最主要的区别就是:c++的内存泄露是开放的,而java则是开启了一个虚拟机封装起来,c++的内存泄露将影响到整一个系统,一旦泄露那么这块内存将一直不可用。java有了虚拟机的保护如果一旦出现内存泄露达到分配虚拟机内存上限时那么系统将会自动kill掉该进程,而不影响其他。

下面就Android日常开发我列举一些常见的内存泄露情况以及避免方式

内存泄露

上图已经整理出了常见的泄露方式还有一些需要说明的:

1.持有Context对象

Android中常见的context对象主要有两种:Activity和Application,其中View对象对整个activity保持引用。

如果有地方持有了相应的view类对象,一旦发生泄漏那么这整个Activity都会出现无法回收的情况。

2.线程之间Handler使用

Handler 本身是异步的,可以使用静态内部类弱引用处理也可以通过生命周期removeCallbacksAndMessages(null);进行销毁,只要及时处理Handler,泄露还是很容易修复的。

3.内部类与匿名内部类持有外部类对象引用

非静态内部类以及匿名内部类会持有一个隐式的强引用,如果该对象没有被回收,那么Activity 就会发生泄露。

其本质可以通过反编译源代码,内部类对象如何访问外部类成员变量,其实是有一个指针强引用了外部类的对象。

此处可以参考:Java内部类详解

4.最小化变量作用域

变量的使用也是值得注意的一点,Java的垃圾回收器会优先在方法执行结束后进行回收,如果将函数级的变量定义到类级别上,那么也就意味着整个垃圾回收器需要等待到该类的所有引用都被回收完成后才能进行垃圾回收。势必会对内存占用造成影响。优化属性的作用域是必须的,同样这也是封装原则,最小化作用域降低了通过包访问变量并减少了耦合。

5.各类注册没有反注册

所有注册,订阅的操作都需要有一个与之相应的反注册,反订阅。

6.webview泄露

webview也是一个大量占用内存控件,如果我们不及时清理WebView的内存,那最后可能会随着内存消耗的不断增加而发生OOM导致程序崩溃。

你可能感兴趣的:(Android 中常见内存泄露的几种情况)