麦都-平台开发组

Android 内存溢出和内存泄漏的区别以及造成的原因

写作时间:2018-11-05

一、原理 

内存溢出(Out of memory):系统会给每个APP分配内存也就是Heap size值,当APP所需要的内存大于了系统分配的内存,就会造成内存溢出;通俗点就是10L桶只能装10L水,但是你却用来装11L的水,那就有1L的水就会溢出 

内存泄漏(Memory leak):当一个对象不在使用了,本应该被垃圾回收器(JVM)回收,但是这个对象由于被其他正在使用的对象所持有,造成无法被回收的结果,通俗点就是系统把一定的内存值A借给程序,但是系统却收不回完整的A值,那就是内存泄漏 

二、两者的关系 

内存泄漏是造成内存溢出(OOM)的主要原因,因为系统分配给每个程序的内存也就是Heap size的值都是有限的,当内存泄漏到一定值的时候,最终会发生程序所需要的内存值加上泄漏值大于了系统所分配的内存额度,就是触发内存溢出 

三、危害 

内存溢出:会触发Java.lang.OutOfMemoryError,造成程序崩溃 

内存泄漏:过多的内存泄漏会造成OOM的发送,同样也会造成相关UI的卡顿现象 

四、造成的原因以及处理 

A、大量的图片、音频、视频处理,当在内存比较低的系统上也容易造成内存溢出 建议使用第三方,或者JNI来进行处理  

B、Bitmap对象的不正确处理(内存溢出) 不要在主线程中处理图片 使用Bitmap对象要用recycle释放  高效的处理大图, 、

C、非静态匿名内部类Handler由于持有外部类Activity的引用所造成的内存泄漏 根据WeakReference对象,对handler使用弱引用,并且调用removeCallbacksAndMessages移除 

D、线程由于匿名内部类runnable持有activity的引用,从而关闭activity,线程未完成造成内存泄漏 把线程改成静态内部类,调用WeakReference来持有外部资源 

E、BraodcastReceiver、File、Cursor等资源的使用未及时关闭 在销毁activity时,应该及时销毁或者回收

 F、static关键字修饰的变量由于生命周期过长,容易造成内存泄漏 尽量少使用静态变量,一定要使用要及时进行制null处理 

G、单列模式造成的内存泄漏,如context的使用,单列中传入的是activity的context,在关闭activity时,activity的内存无法被回收,因为单列持有activity的引用 

在context的使用上,应该传入application的context到单列模式中,这样就保证了单列的生命周期跟application的生命周期一样

 单列模式应该尽量少持有生命周期不同的外部对象,一旦持有该对象的时候,必须在该对象的生命周期结束前制null