OutOfMemoryError和StackOverFlowError异常

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43635659/article/details/102695995

Java虚拟机规范中除了程序计数器,其余的包括虚拟机栈、本地方法栈、堆、方法区和运行时常量池都会出现堆内内溢出异常。

Java堆内存异常

  • 异常种类?
    • OutOfMemoryError异常
  • 何时产生堆内存溢出异常?
    • Java堆是存放对象实例的,只要是不断的创建新的对象,并且保证在对象和GC Roots之间有可达路径能保证避免被垃圾回收机制清楚这些对象,那么堆中的对象就会越来越多,超过了堆的最大容量时就会产生堆内存溢出异常。
  • 如何处理堆内存溢出异常?
    • 首先,对虚拟机启动参数进行更改,使用-XX:HeapDumpOnOutOfMemoryError来Dump出堆转储快照。
    • 然后,使用内存映像分析工具对堆转储快照进行分析,重点是确定内存中的对象是否是有必要的(也就是要确定是发生了内存泄漏还是内存异常)
    • 如果是内存泄露,就可以通过工具进一步找到对象和GC Roots之间的引用链。这样就可以找到泄露对象是通过怎样的路径与GC Roots相关联并导致垃圾回收器无法回收它们。如此掌握了泄露对象的类型信息以及GC Roots引用链的信息,就可以比较准确的定位出泄露对象的位置。
    • 如果是内存溢出,就是对象必须还活着,也就是垃圾回收器不能回收对象,此时一方面可以查看虚拟机参数,看内存参数是否可以调大,另一方面查看源程序看是否有对象的存在的生命周期过长、持有状态时间过长的情况,消除此类对象以减少程序运行期间的内存消耗。

虚拟机栈和本地方法栈内存异常

  • 异常种类?
    • StackOverFlowError异常
    • OutOfMemoryError异常
  • 何时产生异常?
    • 当线程请求的栈深度超过了栈空间允许的深度,会产生StackOverFlowError异常
    • 当栈空间扩展时没有申请到足够的空间,会产生OutOfMemoryError异常
  • 小注:
    • 当栈空间太小(对应请求深度超过了栈空间),还是已使用的栈空间太大(对应申请不到足够的额外空间),栈空间无法分配时,本质上都是由于栈空间出现了问题。
  • 详解产生StackOverFlowError异常:
    • 对于单个线程,当栈空间无法分配时,无论是栈帧太大还是栈内存太小都会出现StackOverFlowError异常
  • 详解产生OutOfMemoryError异常:
    • 对于多个线程情况下,给每个线程栈空间分配的内存越大,越容易产生此类异常。
    • 原因:操作系统分配给每个进程的内存空间是有限的,虚拟机内存可以分为程序计数器、堆、方法区、虚拟机栈和本地方法栈。因为堆和方法区是线程共享的,所以虚拟机通过设置参数来控制堆和方法区的最大内存,剩余的内存等于操作系统的内存减去堆最大内存和方法区最大内存。程序计数器、虚拟机栈和本地方法栈是线程私有的,程序计数器是一块小的内存空间,内存相对可以忽略不计,假设忽略虚拟机本身运行的内存需求,剩下的就是虚拟机栈和本地方法栈的内存。分配给虚拟机栈和本地方法栈的内存越大,那么线程占有的内存就越小,建立线程时就越容易将内存消耗完毕。此时就会出现OutOfMemoryError异常。
  • 如何处理异常?
    • 出现OutOfMemoryError异常时,如果不能减少线程数和更换64位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程空间。
    • 出现StackOverFlowError异常时,可以通过增大虚拟机栈空间。

方法区和运行时常量池内存异常

  • 异常种类?
    • OutOfMemoryError异常
  • 何时产生异常?
    • 当扩展内存时没有申请到足够的内存空间就会出现OutOfMemoryError异常。
  • 异常情况:
    • 方法区中存储的是类信息、字段、方法、接口等,都会出现内存溢出异常。
  • 小注:
    • 方法区出现内存溢出异常是很常见的,在经常动态生成大量Class的应用中,程序中使用了CGLib字节码增强和动态语言之外,大量JSP或动态产生JSP文件的应用、基于OSGi的应用都会产生内存溢出异常。

本机直接内存异常

  • 异常种类?
    • OutOfMemoryError异常
  • 直接内存大小可以通过-XX:MaxDirectMemorySize来指定,如果不指定就会和Java堆最大值一样,DirectByteBuffer分配内存时出现内存溢出异常,并没有真正向操作系统申请分配内存,而是通过计算得知内存无法分配,于是手动抛出异常。
  • 如何处理异常?
    • 如果通过Heap Dump出的文件中没有看见明显的异常,并且发现Dump出的文件比较小,而程序中又直接或者时间接的使用了NIO类,那么基本上可以判定是此类异常。

虚拟机参数

  • -Xms——表示Java虚拟机堆内存初始化分配大小,通常为操作系统可用内存的1/64大小,可以通过实际情况进行分配。
  • -Xmx——表示Java虚拟机堆内存可被分配的最大值,通常为操作系统可用内存的1/4大小。如果二者相等,表示堆内存不可扩展。
  • -XX:PermSize——表示方法区初始化分配内存大小
  • -XX:MaxPermSize——表示方法区可被分配的内存最大值
  • -Xss——栈内存的分配大小
  • -XX:HeapDumpOnOutOfMemoryError——当虚拟机出现内存溢出异常时Dump出内存转储快照文件以便于分析。

猜你喜欢

转载自blog.csdn.net/weixin_43635659/article/details/102695995