内存溢出指程序申请内存时,没有足够的内存供申请者使用。内存溢出就是你要的内存空间超过了系统实际能分配给你的空间,相当于此时系统没法满足你的需求,就会报内存溢出的错误。
最常见的有:栈内存溢出、堆内存溢出
-
栈内存溢出(StackOverflowError)
-
堆内存溢出(OutOfMemoryError:java heap space)
第一步【看报错】:
看报错出现在哪个应用里,这个应用的最近一次发版是什么需求,什么时候,一般都是最近上线的一次需求的代码导致的。
扩展:
JVM提供的内存管理机制和自动垃圾回收极大的解放了用户对于内存的管理,大部分情况下不会出现内存泄漏和内存溢出问题。但是基本不会出现并不等于不会出现,所以掌握Java内存模型原理和学会分析出现的内存溢出或内存泄漏,对于使用Java的用户来说仍然十分重要。
栈溢出:
栈内存可以分为虚拟机栈(VM Stack)和本地方法栈(Native Method Stack),除了它们分别用于执行Java方法(字节码)和本地方法,其余部分原理是类似的(以虚拟机栈为例说明)。Java虚拟机栈是线程私有的,当线程中方法被调度时,虚拟机会创建用于保存局部变量表、操作数栈、动态连接和方法出口等信息的栈帧(Stack Frame)。
具体来说,当线程执行某个方法时,JVM会创建栈帧并压栈,此时刚压栈的栈帧就成为了当前栈帧。如果该方法进行递归调用时,JVM每次都会将保存了当前方法数据的栈帧压栈,每次栈帧中的数据都是对当前方法数据的一份拷贝。如果递归的次数足够多,多到栈中栈帧所使用的内存超出了栈内存的最大容量,此时JVM就会抛出StackOverflowError。
下面我们写一个不断的递归调用自己的方法,然后执行该程序:
从输出信息中发现,出现问题的地方就是程序中递归调用方法自身的地方。
总之,不论是因为栈帧太大还是栈内存太小,当新的栈帧内存无法被分配时,JVM就会抛出StackOverFlowError。通常栈内存可以通过设置-Xss
参数来改变大小。
堆内存溢出:
堆内存的唯一作用就是存放数组和对象实例,即通过new指令创建的对象,包括数组和引用类型。堆内存溢出又分为两种情况:
-
堆内存溢出:当堆中对象实例所占的内存空间超出了堆内存的最大容量,JVM就会抛出
OutOfMemoryError:java heap space
异常 -
堆内存泄露:当堆中一些对象不再被引用但垃圾回收器无法识别时,这些未使用的对象就会在堆内存空间中无限期存在,不断的堆积就会造成内存泄漏
如果是因为堆内存空间太小,可以通过改变-Xmx
来进行调整,或者分析程序中对象的生命周期和存储结构等信息进行调整;如果发生了内存泄漏,则可以先找出导致泄漏发生的对象是如何被GC ROOT引用起来的,然后通过分析引用链找到发生泄漏的地方。