1,问题描述:
新上了一版代码之后,上游服务请求我们服务失败,报错:“服务不可用”,发现注册中心上服务掉线,查询日志:发现oom:Java heap space,GC overhead limit exceeded。
容易发生内存溢出的内存空间包括:PeimanentGeneration space和Heap space。
2,资料收集
OutOfMemoryError: Java heap space 内存溢出的一种,表示由于JVM中堆区不足,导致申请内存的请求无法被满足。通常是因为程序试图分配比堆空间更大的对象,或者是因为内存泄漏,导致程序不断分配内存,不能及时释放不再需要的内存。
OutOfMemoryError: GC overhead limit exceeded 内存溢出的一种,表示执行垃圾收集的时间比例太大,工作时间太少,程序花费了超过98%的时间来进行垃圾回收,而回收的内存少于2%,如果连续多次出现这种情况,就会抛出这个异常。
解决oom的途径:
①增大JVM内存。
②检查程序代码,是否有内存泄漏的地方。
3,解决过程
1,为了不影响上游服务,首先进行服务回滚。
2,检查新上的代码,查看是否有内存溢出的情况。
发现调小了线程池的核心线程数和最大线程数。如果核心线程数太小,可能会导致线程频繁地创建和销毁,增加内存开销
,降低系统性能,但不会导致OOM,而如果这线程池中执行的任务需要大量内存,则也有可能导致OOM。为了验证这个问题
我又将这2个参数改回去了,程序运行一段时间,还是发现有同样的问题,所以这个排除。
3,由于服务启动参数设置了:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/aku-repayment-service
所以当发生oom的时候,系统会自动生成DUMP文件,放在指定路径下。所以分析下这个文件就知道什么地方发生内存泄漏了
什么是DUMP文件?
堆Dump是反应Java堆使用情况的内存镜像,其中主要包括系统信息、虚拟机属性、完整的线程Dump、所有类和对象的
状态等。
使用 Java VisualVM对其进行分析:
byte[]过多,发现是字节数组输入流过多,对程序进行分析,发现只有日志输出和http请求会产生字节数组。日志文件没有进行修改过,所以日志是没问题的,所以产生oom的原因是由于那天请求量比较大的时候导致了oom,问了下测试的同事,发现那天在测相关的需求,所以请求得比较频繁,所以导致了此次的oom,调大了JVM内存参数就没有再出现过了。
4,总结
请求过多导致的oom,调大JVM内存就能解决。