java 代码过长_【java虚拟机】OutOfMemoryError异常

对于jvm虚拟机内存中,除了程序计数器意外,其他虚拟机栈、本地方法栈,方法区、堆都存在溢出的可能。

1.堆溢出

java堆是用来存储对象的,只要保证不断的生成对象,而且让他们的GC root不断掉,而不会引起垃圾回收,这样堆就会由于对象的不断创建而不断变大而溢出。当出现Java堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Java heap space”。先通过内存映像分析,判断是内存溢出还是泄漏。

如果是内存泄露,可进一步通过工具查看泄露对象到GC Roots的引用链。于是就能找到泄露对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收它们的。掌握了泄露对象的类型信息及GC Roots引用链的信息,就可以比较准确地定位出泄露代码的位置。

如果不存在泄露,换句话说,就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx与-Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

-Xmx用来设置你的应用程序(不是JVM)能够使用的最大内存数,如果你的程序要花很大内存的话,那就需要修改缺省的设置,比如配置tomcat的时候,如果流量啊程序啊都很大的话就需要加大这个值了,BUT不要大得超过你的机器的内存。

另一个-Xms用来设置程序初始化的时候内存栈的大小,增加这个值的话你的程序的启动性能会得到提高。不过同样有前面的限制,以及受到-Xmx的限制。

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

通过-xss可以设置栈的大小

当线程所需要的栈深度大于虚拟机所设置的允许的栈大小时候,会出现StackOverflowError异常。

当虚拟机想要扩充栈的数量而缺少内存空间时候,就会出现outofmemoryError异常。

3.运行时常量池溢出

方法区与java堆一样,是各个线程共享的内存区域,它用于储存已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

方法区中其实还有一块运行常量池,当class文件中的常量池在类加载之后就被放入运行常量池,运行常量池还可以通过String.intern将常量放入进去,因此其具有动态性,一旦方法区中空间不足时候会抛出OutofMemoryerror异常。

4.方法区溢出

通过不停的类加载去产生大量的类,造成方法区中存放太多的类信息等而溢出、

设置-XX:PermSize持久代初始值和-XX:MaxPermSize持久代最大值参数

5.元数据溢出

在jdk1.8中方法区溢出变成了元数据溢出

6.直接内存溢出

DirectMemory 容量可通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与 Java 堆最大值(-Xmx指定)一样,下面程序利用 DirectByteBuffe 模拟直接内存溢出的情况。

  • Hibernate 的 Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象。
  • 使用 Netty 的堆外的 ByteBuf 对象,在使用完后,并未归还,导致使用的一点一点在泄露

当出现了内存溢出,你怎么排错?

  • 1、首先,控制台查看错误日志。
  • 2、然后,使用 JDK 自带的 jvisualvm 工具查看系统的堆栈日志。
  • 3、定位出内存溢出的空间:堆,栈还是永久代(JDK8 以后不会出现永久代的内存溢出)。
    • 如果是堆内存溢出,看是否创建了超大的对象。
    • 如果是栈内存溢出,看是否创建了超大的对象,或者产生了死循环。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值