最近腾出时间来整理整理android面试中常被面试官面到的技术点,今天就来收集一下内存溢出和内存泄露问题。
内存泄露的常用定义:
Java的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度。我们有时也将其称为“对象游离”
Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收;另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达,同样会被GC回收
一个程序中,已经不需要使用某个对象,但是因为仍然有引用指向它的垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,就这样造成了内存泄露。
常见的内存泄露:
一、注册BroadcastReceiver,ContentObserver,FileObserver,以及一些其他的监听器(电话监听器),在Activity销毁的时候忘记注销,一定要unregister掉,否则这个Ac对象就会
被上述的这些对象持有导致不能被GC。
二、查询数据库返回的Cursor没有及时关闭,InputStream/OutputStream没有关闭,所以这类问题最后在try{}catch()的finally{关闭cursor和流的操作}
三、Handler 也会导致内存泄露,主要是Handler 属于Thead Local 中的变量,所以Handler的生命周期和Activity是不一致的,所以当Handler持有了Activity的引用是,就可能存在Activity Destory的时候当前AC不能被GC.解决方案有两种,一种是Handler申明为静态内部类,不持有外部类的引用,然后也持有外部Ac的虚引用,平常我的处理就是在onDestory的时候handler.removeAllCallbackAndMessage(null);
四、Bitmap使用后未调用recycle(),这一条我觉得和泄露无关,还有cursor以及流的关闭,我个人觉得应该只是可能会导致内存溢出,因为我没看到有什么相关的引用持有这类对象,可能只是在需要连续分配大量内存的时候可能会造成内存的溢出。如果有谁看到这儿的话,并且有不一样的理解的时候希望能再下面留言帮我解答一下疑惑。
五、static关键字 当类的成员变量声明成static后,它是属于类的而不是属于对象的,如果我们将很大的资源对象(Bitmap,context等)声明成static,那么这些资源不会随着对象的回收而回收,而当这些静态变量持有了Activity的引用的时候,内存泄露基本就在所难免了。所以慎用static
六、复用convertView 同样的是控制内存溢出的解决方案。
总结:在开发中怎样避免这两类问题
1、不要保持对activity的持久引用,尽量使用application代替activity
2.良好的代码规范,清晰代码逻辑
3.对于引用生命不一样的对象,可以用弱引用WeakReferner
4.对于资源对象 使用finally 强制关闭
5.内存压力过大就要统一的管理内存
6.对象重复并且频繁调用可以考虑对象池。
7.关注全局性的集合、单例模式的使用、类的static变量等等。在Java的实现过程中,也要考虑其对象释放,最好的方法是在不使用某对象时,显式地将此对象赋空。最好遵循谁创建谁释放的原则。
8.使用软引用和弱引用