本文转载自微信公众号《小姐姐的味道》,作者小姐姐养的狗。转载本文请联系味觉小姐公众号。Java进程突然消失了,日志中没有关于它们的任何信息,它们只是凭空蒸发了。日志和OOM的一些配置参数根本没有用。不要恐慌。一个过程没有灵魂。重新启动将使这些程序再次活跃起来。问题就是重启解决不了的问题,背后有墨菲定律在默默运作。谁杀死了心爱的Java进程?不要太绝情。在你死之前,至少让过程表达一些遗言。本篇小文将分析Java进程消失的几个常见谜团,让你静下心来,看花开花落。他们可能:被操作系统判断,执行god函数,被队友埋葬,使用错误的启动方式,记录系统配置错误1.被操作系统判断,以下问题不止一个小小遇到过伙伴:我的java进程什么都没有,什么都没有,只是蒸发消失了。为什么?是因为感情太多,对象太多?这是一个非常有趣和有技巧的问题。执行dmesg命令,很有可能你会看到你的进程崩溃信息躺在那里。为了能够看到发生的时间,我们习惯性的加上参数Tdmesg-T,很明显是因为操作系统不喜欢你的进程,给Kill了。这种现象与Linux内存管理有关。由于Linux系统采用了虚拟内存分配方式,JVM代码、库、堆和栈的使用都会消耗内存,但是申请的内存,只要没有被实际访问过,是不算的,因为没有真正的对其进行物理分配。页。随着内存的使用,越来越多的内存被使用。第一层保护是SWAP;当SWAP快用完时,会尝试释放缓存;当两种资源都耗尽时,杀手就会出现。oomkiller会在系统内存耗尽的时候跳出来,有选择地杀掉一些进程,以腾出一点内存。所以这个时候,我们的Java进程就被操作系统“主动”终止了,JVM连最后一句话的机会都没有。此信息只能在操作系统日志中找到。解决这类问题,首先不要太贪心。例如,在一台总共有8GB的??机器上,您已经为JVM分配了完整的7.5GB。当操作系统内存不足时,您的JVM可能会成为oom-killer的牺牲品。但是,可以通过以下命令来防止进程被判断。echo-17>/proc/[PID]/oom_adj这是因为oom_adj文件是oomkiller杀死的进程的权重,一般在[-17,15]之间。更高的权重意味着更有可能被oomkiller选择。执行此操作后,您的Java进程将获得特权并且可以忽略规则。2.执行上帝功能。xjjdog对这个功能的评价是:不知道总比知道好。别看我有这个功能。是你,System.exit。这个函数很危险,它会强行终止我们的应用程序,什么都不留下。您应该扫描您的代码以确保不存在此类逻辑。相信我,你不需要使用程序判断来立即结束进程,尤其是在业务系统中。如果是这样,大概率是不合理的。除非你使用Java作为脚本。这个功能是一个非常高级的埋点技巧,尤其是在Android等应用中。如果应用程序崩溃,您将无法分析原因,即使您执行ShutdownHook。使用退出功能时,一定要客气。当然,我们对此并非束手无策。下面这段代码可以阻止exit的执行,很霸道。神之手也断了回去。importjava.security.Permission;publicclassS{privatestaticclassExitTrappedExceptionextendsSecurityException{}privatestaticvoidforbidSystemExitCall(){finalSecurityManagersecurityManager=newSecurityManager(){publicvoidcheckPermission(Permissionpermission){if(permission.getName().startsWith("exitVM")){thrownewExitTrappedException();}}};System.setSecurityManager(securityManager);}privatestaticvoidenableSystemExitCall(){System.setSecurityManager(null);}publicstaticvoidmain(String[]args){forbidSystemExitCall();try{System.exit(0);}catch(Exceptionex){ex.printStackTrace();}System.out.println("谢谢xjjjdog,我还能执行");}}如果你什么都试过了,还是找不到异常终止的原因,试试挂这段代码。这可能会挽救生命。3.错误的启动方式下面说说最常见和最常见的一种会导致应用程序意外死亡的情况:那就是错误的Java程序启动方式。很多同学对Linux不是很熟悉,使用XShell登陆后,调用如下命令启动。javacom.cn.AA&这个同学还是有点自觉的,用了末尾的&号期望进程在后台运行。但遗憾的是,很多情况下,随着XShellTab页面的关闭或者等待超时,后续的Java进程会一起停止,非常混乱。正确的启动方式是使用nohup关键字,或者阻塞在其他寿命更长的进程中(比如docker)。nohupjavacom.cn.AA&所以,在登录终端tty的时候,一定要了解父进程当前在执行谁。您可能是接下来要运行的所有进程的祖先。4、日志配置错误如果不是以上原因,那么很大概率是你项目中的日志框架配置有误。Java中的日志框架有很多,配置方式也多种多样。一不小心就会踩坑。即使使用SpringBoot,也会因为依赖包问题导致启动问题。日志配置错误+异常,当然什么都不会留下。使用以下命令将依赖树转移到日志文件中进行分析。如果mvndependency:tree>dep.log是一个SpringBoot项目,可以在主类中添加一些代码。publicstaticvoidmain(String[]args){try{SpringApplication.run(LinkpowerDtulockApplication.class,args);}catch(Exceptione){System.out.println(e);}}如果有异常情况可以发现早期的。此外,还有一些奇怪的原因。比如磁盘满了,句柄不够用。这些情况都非常隐蔽,需要你对系统的细节进行准确的把控。进程的无声死亡通常会使我们的故障排除更加困难。通常,我们关闭一个服务时,我们使用“kill-15”而不是“kill-9”,这样服务就可以在死之前喘口气。但它并不总是有效,因为程序从来没有机会说出它的最后一句话,更高的东西阻止了它。Java进程快要死了,我们只能另寻他法。作者简介:品味小姐姐(xjjdog),一个不允许程序员走弯路的公众号。专注于基础架构和Linux。十年架构,每天百亿流量,与你探讨高并发世界,给你不一样的滋味。我的个人微信xjjdog0,欢迎加好友进一步交流。
