深入理解JVM之OutOfMemory异常

内存溢出(Memory Overflow):实实在在的内存空间不足导致;

内存泄漏(Memory Leak):该释放的对象没有释放,多见于自己使用容器保存元素的情况下。

1  Java堆溢出

  用映像内存工具辨析究竟是内存泄露还是内存溢出,如果是内存泄露,可以进一步用工具找到泄露对象;如果是内存溢出,可以调大虚拟机堆参数或者从代码上检查是否存在某些对象生命周期过长、持续时间过长、循环不停分配对象的情况,尝试优化代码减少内存消耗。

  参数 : -Xms5m -Xmx5m -XX:+PrintGC

  出现java.lang.OutOfMemoryError: GC overhead limit exceeded  一般是(某个循环里可能性最大)在不停的分配对象,但是分配的太多,把堆撑爆了。

  出现java.lang.OutOfMemoryError: Java heap space一般是分配了巨型对象

2  Java虚拟机栈和本地方法栈溢出

  一般的方法调用是很难出现的,如果出现了要考虑是否有无限递归。

  虚拟机栈带给我们的启示:方法的执行因为要打包成栈桢,所以天生要比实现同样功能的循环慢,所以树的遍历算法中:递归和非递归(循环来实现)都有存在的意义。递归代码简洁,非递归代码复杂但是速度较快。

  StackOverflowError异常:线程请求的栈深度大于虚拟机所允许的栈深度

  OutOfMemoryError异常:可动态扩展的JAVA虚拟机栈在扩展时无法申请到足够的内存时

  这两种异常有相互重叠的地方就是当栈空间无法继续分配时,究竟时内存太小,还是已经使用的栈空间太大,本质是同一个问题。实验表明,单线程环境下,无论是栈帧太大还是虚拟机栈容量太小,当内存无法分配时,都抛出的时StackOverflowError异常。要想抛出OutOfMemoryError,只有不断的建立线程。实际生产中,如果是建立过多线程导致的内存溢出,在不减少线程数或者更换64位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程。以“减少内存”的方式,解决内存溢出问题。

3 方法区和运行时常量池溢出

方法区又交永久代,永久代溢出有以下几种情况:

  1.动态生成大量的class

  2.大量jsp和动态产生jsp。

4 本机直接内存溢出

  DirectMemory容量可通过-XX:MaxDirectMemorySize指定,若不指定,默认与Java堆最大值(-Xmx)一样

  jdk提供的直接在内存上分配空间的类

  public class DirectMem {

         public static void main(String[] args) {

                ByteBuffer b = ByteBuffer.allocateDirect(1024*1024*14);

         }

  }

  运行:outOfMemoraryError:direct buffer memory

  配置:-Xmx 10m –XX:MaxDirectMemorySize=10M

posted @ 2019-03-14 14:22  懒懒惰惰一只猫  阅读(467)  评论(0编辑  收藏  举报