Java JVM内存结构中的OOM与StackOverFlowError

StackOverFlowError

出现原因:深度递归调用(普遍由于没有设置有效的递归出口),造成jvm中虚拟机栈超过预设的大小
解决方法
1.查看递归逻辑
2.逻辑正确的情况下,我们可以使用参数-Xss选项来设置线程的最大栈空间,栈的大小直接决定了函数调用的最大可达深度。 (IDEA设置方法:Run-EditConfigurations-VM options 填入指定栈的大小-Xss256k)
代码演示

/**
 * 演示栈中的异常
 *
 * 默认情况下:count 10818
 * 设置栈的大小: -Xss256k count 1872
 */
public class StackErrorTest {
    private static int count = 1;
    public static void main(String[] args) {
        System.out.println(count);
        count++;
        main(args);
    }
}

OOM(OutOfMemoryError)

java.lang.OutOfMemoryError:Java heap space

出现原因:在创建新的对象时, 堆内存中的空间不足以存放新创建的对象
即:新建对象(new),对象存入堆空间时,在堆空间的年轻代与老年代进行了垃圾回收后仍然无法存入(堆空间已达到Xmx,或堆空间满且不允许扩容)此时会抛出
java.lang.OutOfMemoryError:Java heap space
解决方法

  1. 增大堆内存,但往往只起到延迟的作用,治标不治本
  2. 通过Plumbr 等辅助工具分析堆内存使用情况,后对代码进行改进

java.lang.OutOfMemoryError:GC overhead limit exceedec

出现原因:执行垃圾收集的时间比例太大, 有效的运算量太小(GC花费的时间超过98%,且所回收内存低于2%)。系统判定垃圾回收的时间过长,为避免恶性循环 浪费CPU性能,会抛出
java.lang.OutOfMemoryError:GC overhead limit exceedec
解决方法

  1. 可以通过配置以下参数解决GC overhead limit exceedec
    但是此方法往往只能拖延OOM出现的时间,到最后还得进行其他处理。而且会将原有的java.lang.OutOfMemoryError:GC
    overhead limit exceedec转变为java.lang.OutOfMemoryError:Java heap space
-XX:-UseGCOverheadLimit
  1. 有时候触发 GC overhead limit 错误的原因, 是因为分配给JVM的堆内存不足。这种情况下只需要增加堆内存大小即可。
    在大多数情况下, 增加堆内存并不能解决问题。例如程序中存在内存泄漏, 增加堆内存只能推迟产生 java.lang.OutOfMemoryError: Java heap space 错误的时间。

java.lang.OutOfMemoryError:Direct buffer memory

写NIO程序时经常使用ByteBuffer来读取或者写入数据,这是一种基于通道(channel)与缓冲区(buffer)的I/O方式,他可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用操作,这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据
ByteBuffer.allocate(caoability)第一种方式是分配JVM堆内存,属于GC管辖范围,由于需要拷贝所以速度相对较慢
ByteBuffer.allocateDirect(caoability) 第2种方式是分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝所以速度相对较快。
但如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象们就不会被回收,这时候堆内存充足,但本地内存可能已经使用光了,再次尝试分配本地内存就会出现OOM
引用博文

java.lang.OutOfMemoryError:unable to create new native thread

出现原因:java应用进程创建了过多的线程,一个应用进程所创建的线程数,超过系统承载极限

解决方案
通过Plumbr 等辅助工具分析堆内存使用情况,后对代码进行改进

java.lang.OutOfMemoryError:Metaspce

出现原因:元数据区(Metaspace) 已被用满,Metaspace 的使用量与JVM加载到内存中的 class 数量或大小有关。 java.lang.OutOfMemoryError: Metaspace 错误的主要原因, 是加载到内存中的 class 数量太多或者体积太大。

解决方法

  1. 增加 Metaspace 的大小,可以通过设置XX:MaxMetaspaceSize参数
-XX:MaxMetaspaceSize=512m
  1. 直接去掉 Metaspace 的大小限制。注意如果服务器/本机物理内存不足有可能会引起内存交换(swapping), 严重拖累系统性能。(不推荐

关于Metaspace

Java 8 之后的版本使用metaspace(元数据区/元空间) 来替代永久代
在这里插入图片描述
metaspace 是方法区在HotSpot虚拟机中的实现,它与永久代最大的区别在于:metaspace并不在虚拟机内存中而是使用本地内存

存储信息如下:

  • 虚拟机加载的类信息
  • 常量池
  • 静态变量
  • 即时编译后的代码
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值