一、内存溢出和内存泄漏的概念理解
**内存溢出:**是指程序代码片段被执行申请内存时,没有足够的内存空间,导致OOM异常。
OOM:即内存溢出,out of momery。
Android系统为每一个应用程序申请的内存是有限的(为什么如此设计,在dalvik虚拟机章节已经说明),一般为64M或者128M等,国内手机产商修改rom后,也会有所不同。
我们可以在清单文件中配置android:largeheap=“true”,从而可给app申请更大的手机内存空间。
**内存泄漏:**内存泄漏是指程序在申请内存后,被某个对象一直持有而无法释放已申请的内存空间。内存泄漏不断堆积,应用程序可申请的内存空间就会越来越少,最终可能就出现,当程序片段被执行申请新的内存空间而不得,最终导致内存溢出。
内存泄漏是因,内存溢出是果。针对于内存溢出,除了手机内存小,应用程序本身申请的大对象内存多(比如没有合理的处理bitmap),内存泄漏是导致内存溢出的一个重要的原因。
故,在做我们的应用程序的内存优化的时候,内存溢出排查也是其中的一个重要方面。
二、内存溢出分类
1、栈内存溢出
栈内存溢出:StackOverflowError,方法被运行在虚拟栈中,在虚拟栈中的执行的命令递归执行,如果递归的深度过大,则可能会导致栈溢出。通过一下case,可以模拟栈内存溢出。
public class StackOverflowCase {
//模拟一个递归方法调用
public void stackOverflowMethod(){
stackOverflowMethod();
}
public static void main(String[] args) {
StackOverflowCase stackOverflowCase = new StackOverflowCase();
stackOverflowCase.stackOverflowMethod();
}
//main函数运行后,会抛出Exception in thread "main" java.lang.StackOverflowError
}
2、堆内存溢出
堆内存溢出:OutOfMemoeryError,Java中被创建的对象实例,所占用的内存空间过大,超出了当前应用进程能获取的最大内存空间。
堆内存溢出,是非常常见的,日常开发当中,有很多案例可能导致堆内存溢出,在第三节中会对堆内存泄漏的案例做详细分析。内存泄漏终将导致内存溢出。除了内存泄漏之外,常见的内存溢出场景有:
1)类结构没有声明好,导致的内存溢出,比如fastJson解析json串的时候,出现了对象之间的相互引用。
2)对象所申请的内存过大,比如在android应用开发中,经常会用到的大图加载,bitmap的对象占用大量内存,所以,我们有各种三方图片加载库,大多通过缓存算法,解决图像占用过大的内存。
3)内存泄漏,并不会理解导致我们的应用程序瘫痪,但是溢出的持续积累,终将导致内存溢出。
3、持久代内存溢出
持久代中包含方法区,方法区中包含常量池,持久代内存溢出包括:
1)运行时的常量池溢出 2)方法区中保存的class对象没有及时被回收掉或者class信息占用的内存过大导致溢出。用String.intern()可以触发常量池溢出。
三、内存泄漏的场景案例
1、单例模式下的内存溢出
代码案例:
class AppSetting {
private static AppSetting ourInstance = null;
public static Context mContext;
static AppSetting getInstance(Context context) {
if(ourInstance!=null){