再说内存问题,Android系统底层的沙盒模型实在是太高明了,使得应用的开发对内存使用的安全性(指的是对系统运行来说)大大提升,所以呢,应用开发人员往往容易忽视内存问题,本来嘛,使用Java语言大家都没有习惯性紧张内存。由于忽视这个问题,所以啊,很多OOM的情况就悄然发生啦。诚然Java是不需要主动回收内存,但是哥儿们还是要注意别泄露了呀,自己写代码要当心,使用Android的SDK也得当心哦(系统有很多潜在的“陷阱”哦,需要正确的使用来避免的)。
内存泄露本质上就是对象的生命周期超出了程序设计的周期,不该存在的时候你还在坚挺着。主要就是一个不再使用的对象还在被一个正在使用的对象或者是无法回收的GC Root所引用,常见的GC Root主要有哪些呢,可以参考大侠的译帖:http://blog.csdn.net/fenglibing/article/details/8928927 ,表象那就各种各样咯,在Android上最主要就是Activity或者Context的泄露(最简单的办法就是尽量使用Application的context来替代)。
下面要说的是几种比较不容易发现的情况,大家写代码的时候要注意:
1、使用handler,一般大家在用的时候喜欢当成一个内部类来使用,然后处理一些Runnable或者Message,这个handler是会引用到当前的外部类的一般是Activity,并且当handler有未处理完的事情时这个对象是不会被回收的也就意味着当前的Activity也是不会回收的。这种情况可以将handler变成一个static的内部类,这样就隔离了与外部类的引用关系(但是会出现一个问题,就是外部对象的Context无法直接引用到了,可以在Handler中保存一个Activity对象的弱引用);另外也可以再Activity退出时将handler中的未执行操作和未处理的Message移除掉。
class ExHandler extends Handler {
private WeakReference<Activity> ac;
public ExHandler(Activity a) {
this.ac = new WeakReference<Activity>(a);
}
}
2、Message的使用,大家可以看Message的源码,里面有一个private static Message sPool;还有一个Message next;这是注释中实现global pool的关键,就是组成了一个链表从而管理所有缓存的Message。所以Android是推荐大家使用obtain的方式来重复使用Message是更有利于性能的提升。 http://bj007.blog.51cto.com/1701577/649064
3、在JAVA中String的split操作也会造成内存的问题,因为在实现上为了高效,这个方法其实是采用索引的方式将字符串分割的并没有新创建一个字符串对象,这个优化某些时候也会造成内存问题,比如我们解析了一个很大的String结构,但是我们最后仅仅需要保持中间的某一段,我们直接保持split操作后的结果也就是保持了整个String的引用,我们解决这个问题可以这样,重新new一个String出来存储中间的某一段值。同样的问题在json解析时也是存在的。
4、在使用绑定远程服务时,需要将获取到的IBinder使用完后置于空相信大家都不会忘记,因为这个对象保存了对远程对象的引用,还有一个使用方式也同样需要注意,使用Messenger和Message相互通信,大家也同样要注意不要一直保持对远程对象的引用,这个里面replyTo尤为要记得。
5、文件句柄和cursor,大家都知道用完需要关闭,但是这两个东西在使用过程中是可能出现异常的(包括一些API本身声明会抛出异常,还有可能的一些异常操作),所以最好它们的关闭在try结构中的finally中去执行,这样才最安全。还要特别注意的一点是嵌套情况的关闭顺序。
6、JNI层的内存泄露,C++内存泄露在Android上不太好查,大家写代码的时候要注意主动释放内存哦。