jvm问题排查

  1. 内存泄漏:指程序在申请内存之后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积的后果就是内存溢出。
  2. 内存溢出:指程序申请内存时,没有足够的内存供申请者使用,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。
  3. 二者的关系:
    1>内存泄漏的堆积最终会导致内存溢出
    2>内存溢出就是你要的内存空间超过了系统实际分配给你的空间,此时系统相当于没法满足开发人员的需求,就会报内存溢出的错误。
    3>内存泄漏是指向系统申请内存进行使用(new),可是用完了以后却不归还(delete),最后该内存不能再被访问和使用。
    4>内存溢出,分配的内存不足以放下数据。
  4. 内存泄漏的分类:
    1.常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
    2.偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作下才会发生。
    3.一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法的缺陷,导致总有一块内存发生泄漏。
    4.隐式内存泄漏,程序在运行的过程中不停的分配内存,直到结束时才释放。
  5. 内存溢出的原因及解决方法。
    1>内存中加载的数据量过于庞大,如一次从数据库中取出过多数据。
    2>集合类中有对对象的引用,使用完后未清空,使得jvm不能回收。
    3>代码中存在死循环或者循环或循环产生过多重复的对象实体。
    4>使用的第三方软件中的bug。
    5>启动参数内存值设定的过小。
  6. OOM出现的场景

1>堆溢出

java.lang.OutOfMemoryError: Java heap space

原因
1.代码中可能存在大对象分配
2.可能存在内存泄漏,导致在多次GC之后,还是无法找到一块足够大的内存容纳当前对象
解决方法
1.检查是否存在大对象分配,最有可能的是大数组分配。
2.通过jmap命令,把堆内存dump下来,使用mat工具分析一下,检查是否存在内存泄漏的问题
3.如果没有找到明显的内存泄漏,使用-xmx加大内存
4.检查是否有大量自定义的finalizable对象,也有可能是框架内部提供的,考虑其存在的必要性。
2>永久代/元空间溢出

java.lang.OutOfMemoryError: PermGen space
java.lang.OutOfMemoryError: Metaspace

原因
永久代是HotSot虚拟机对方法区的具体体现,存放了被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等。JDK8后元空间替换了永久代,元空间使用的是本地内存,还有其他细节变化。

  • 字符串常量由永久代转移到堆中
  • 和永久代相关的jvm参数已移除
    1.在java7之前,频繁的错误使用String.intern()方法
    2.运行期间生成了大量的代理类,导致方法区被撑爆,无法卸载。
    3.应用长时间运行,没有重启
    解决方法
    1.检查是否永久代空间或元空间设置的过小
    2.检查代码中是否存在大量的反射操作
    3.dump之后通过mat检查是否存在大量由于反射生成的代理类
    4.重启jvm

3>GC overhead limit exceeded

java.lang.OutOfMemoryError:GC overhead limit exceeded

原因:
这个是JDK6新加的错误类型,一般都是堆太小导致的。
Sun官方对此的定义:超过98%的时间来做GC并且回收了不到2%的堆内存时会抛出此异常。
解决方法:
1.检查项目中是否有大量的死循环或者有使用大内存的代码,优化代码。
2.添加参数 -XX:-UseGCOverheadLimit 禁用这个检查,其实这个参数解决不了内存问题,只是把错误的信息延后,最终出现 java.lang.OutOfMemoryError: Java heap space。
3.dump内存,检查是否出现内存泄漏,如果没有,加大内存。
4>方法栈溢出

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

原因:
出现这种异常,基本上都是创建了大量的线程导致的
解决方法:
1.通过-Xss降低每个线程栈大小的容量
2.线程总数也受到系统空闲内存和操作系统的限制,检查是否该系统下有此限制:

/proc/sys/kernel/pid_max
/proc/sys/kernel/thread-max
maxuserprocess(ulimit -u)
/proc/sys/vm/maxmapcount

5>分配超大数组

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

这种情况一般是由于不合理的数组分配请求导致的,在数组分配之前,jvm会执行一项检查。要分配的数组在该平台是否可以寻址(addressable),如果不能寻址,就会抛出异常。

6>swap溢出

java.lang.OutOfMemoryError: Out of swap space

原因:
1.swap分区大小分配不足。
2.其他进程消耗了所有内存。
解决方案:
1.其他服务进程可以选择性的拆分出去。
2.加大swap分区大小,或者加大机器内存大小。
7>本地方法溢出

java.lang.OutOfMemoryError: stack_trace_with_native_method

本地方法在运行时出现了内存分配失败,和之前的方法栈溢出不同,方法栈溢出发生在jvm代码层面,而本地方法溢出发生在JNI代码或本地方法处。

7.内存溢出排查工具
hprof文件:hprof文件是java进程的内存镜像文件,里面包含了内存堆详细的使用信息,即某个时间点,java进程的内存快照。
1>
可以在jvm参数配置的时候加上,-XX:+HeapDumpOnOutOfMemoryError ,项目发生OutOfMemoryError内存溢出时保存堆快照。
2>
使用 arthas heapdump下载内存溢出的文件,出现内存溢出报错时执行该命令。
使用MAT工具定位

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值