深入理解JVM的一个重要目的就是解决实际生产中的出现的异常,并能从根上处理问题。JVM定义的异常有哪些呢?见下表:

    实战OutOfMemoryError异常_内存溢出

   除了计数器未定义异常,其他都会有OutofmemoryError的异常,下面就实战这几个部分的异常:

  一、Java heap溢出异常    

    堆内存中主要存放对象、数组等,只要不断地创建这些对象,并且保证 GC Roots 到对象之间有可达路径来避免垃圾收集回收机制清除这些对象,当这些对象所占空间超过最大堆容量时,就会产生 OutOfMemoryError 的异常。

    实战OutOfMemoryError异常_数据_02

     实战OutOfMemoryError异常_最大深度_03

    堆溢出异常常见原因 如下:

      1、内存中加载的数据过多,如一次从数据库中取出过多的数据;

      2、集合对对象引用过多且使用完后没有清空;

      3、代码中存在死循环或循环产生过多重复对象;

      4、堆内存分配不合理。

     示例中内存溢出属于第三种,死循环产生过多重复对象。

  二、JVM stacks和native method stacks溢出异常

    Java虚拟机规范》 中描述了两种异常:

      1) 如果线程请求的栈深度大于虚拟机所允许的最大深度, 将抛出StackOverflowError异常。

      2) 如果虚拟机的栈内存允许动态扩展, 当扩展栈容量无法申请到足够的内存时, 将抛出 OutOfMemoryError常。

    下面就进行实战测试:

      实战OutOfMemoryError异常_数据_04

       实战OutOfMemoryError异常_死循环_05

     到达最大深度19237后,栈溢出。

  三、MetaSpace溢出异常(运行时常量池和方法区)

    实战OutOfMemoryError异常_java_06

     实战OutOfMemoryError异常_数据_07

  四、直接内存溢出异常

    直接内存(Direct Memory) 的容量大小可通过-XXMaxDirectMemorySize参数来指定, 如果不去指定, 则默认与Java堆最大值(由-Xmx指定) 一致。

    实战OutOfMemoryError异常_死循环_08

     实战OutOfMemoryError异常_java_09