前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java进程异常退出

Java进程异常退出

作者头像
用户7886150
修改2020-12-15 10:38:03
3.9K0
修改2020-12-15 10:38:03
举报
文章被收录于专栏:bit哲学院

参考链接: Java中的异常

今天,内网测试服务器A总是运行一段时间就服务器进程自行退出了,给出了“Java Result :137”这样的错误码。上网查了一下这个137,感觉没有啥有价值的东西。一开始怀疑项目中的JNI调用崩溃到底层,但是没有看到core.*这样的崩溃日志,同时也没有发现OOM的日志,也没有常见的Java 的堆异常log,关键是同样的环境,另外一台机器B,压力远比这个大,都稳定运行很长时间没有问题。下午又崩溃了两三次,一度怀疑Java是不是有什么bug,不过这个想法立马被我否认了,先从自己找原因。 

      晚上,处理完手里的其他事,到家都十一点了,觉得这个崩溃解决不了,就没法睡觉。拿起手机,随意搜了一下“JAVA进程无端退出”,看到了一篇博客提出一个运维神指令dmesg(ps:有时候这个真是救命的神指令)可以查到一个进程的异常信息,在故障诊断方面非常有用。抱着死马当活马医的想法,在出问题的机器敲了一下“dmesg -T | grep java”,看到了“memory cgroup out of memory ,processor kill ....”,这下舒了一口气,JVM进程退出的原因算是知道了,被系统杀掉了,难怪看不到log。 

     不过为什么被杀呢,查了一下cgroup(详情https://blog.csdn.net/huang987246510/article/details/80765628),了解cgroup是Linux提供一种管理系统资源的机制,尤其是控制虚拟机资源或者docker资源有广泛的应用。由于之前知道这个机器A的内存是足够大,为什么内存足够确使用呢。另外一个机器B在同样的JVM虚拟机配置下却可以。通过查询,我发现Docker可以对系统资源进行设置。这里我注意到Docker,猜想这个机器是不是有什么特殊的,这个机器是不是个docker并且限制了内存,但是Java并不能感知到这种限制。想到之前,在通过TOP 观察java进程使用内存,总是徘徊在某个定值附近,大量的内存不被使用,我查了一下docker相关知识,了解到docker通过cgroup机制,实现进程之间诸如CPU,内存,文件系统,网络等资源的隔离,而一些从执行环境收集信息的应用程序已经在 cgroups 存在之前就被执行了。“top”,“free”,“ps”,甚至 JVM 等工具都没有针对在容器内执行高度受限的 Linux 进程进行优化。详情:https://fabiokung.com/2014/03/13/memory-inside-linux-containers/;所以这些收集程序的信息是不准确,只能反映物理机的状况。至此,我假想这个A是个Docker,并且内存做了一定的限制,并且这个限制低于Xmx的设置,从而在运行时,Java堆内存在分配的时候超过了Docker的限制,就触发了cgroup的资源管理机制,在进程组使用的内存达到限额再申请内存,就会触发OOM(out of memory),从而导致进程退出,后来经过和运维同学确认这个机器配置,符合我的猜想,Docker且内存限制8G(低于设置的Xmx12G)。我修改一下Xmx,问题得以解决。 

    上述只是临时解决了问题,有没有更好的办法让Java自己感知到Docker的资源配置呢,比如内存和CPU等。幸运的是,JDK在1.8u131+及java9以后已经考虑这些问题,并且加入了实验性支持参数。具体来说,可以分为两个方面: 

一、CPU限制,即如果没有显式指定-XX:ParalllelGCThreads 或者 -XX:CICompilerCount, 那么JVM使用docker的cpu限制。如果docker有指定cpu limit,jvm参数也有指定-XX:ParalllelGCThreads 或者 -XX:CICompilerCount,那么以指定的参数为准; 

二、内存限制,通过加上-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap才能使得Xmx感知docker的memory limit;默认情况下,通过java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal可以看到 bool UseCGroupMemoryLimitForHeap = false {experimental} 是关闭的,需要手动打开;打开方式也比较简单,在项目启动参数加上 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap,这样JVM的堆内存将取Xmx和Docker设置的最小值,至此圆满解决问题。 

总结: 

1、在无异常log情况,应用退出,可以先考虑系统中断,dmesg查询相关信息 

2、docker环境会影响应用,使用需要慎重,尤其是开发者和运维人员分离的情况下,开发者应该尽量了解到运维对系统的设置。 

3、JVM的-XX参数需要了解,虽然大部分没有用,但是有些参数对系统优化非常有价值 

下面是官方对Docker支持的文档,不再翻译赘述。 

https://blogs.oracle.com/java-platform-group/java-se-support-for-docker-cpu-and-memory-limits 

参考文献:https://blog.csdn.net/green1893/article/details/78192017?utm_source=blogxgwz4

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档