解析Java横死之谜,气定神闲看花开花落

开发 后端
Java进程突然不见了,日志里并没有任何它们的信息,它们就那么凭空蒸发了。日志、OOM的一些配置参数,根本就不顶用。

[[358408]]

本文转载自微信公众号「小姐姐味道  」,作者小姐姐养的狗 。转载本文请联系小姐姐味道公众号。

Java进程突然不见了,日志里并没有任何它们的信息,它们就那么凭空蒸发了。日志、OOM的一些配置参数,根本就不顶用。

不要惊慌。进程没有灵魂。一个restart,会让这些程序活蹦乱跳again。

问题是那些restart也无法解决的问题,还有默默在背后运作的墨菲定律。

是谁杀死了心爱的Java进程?

不要太绝情,在死之前,起码要让进程发表一点遗言吧。本小篇将分析几种常见的Java进程消失之谜,让你气定神闲看花开花落。

它们有可能:

  • 被操作系统审判了
  • 执行了上帝函数,被队友埋坑了
  • 使用了错误的启动方式
  • 日志系统配置错误

1. 被操作系统审判了

以下问题已经不止一个小伙伴遇到了:我的java进程没了,什么都没留下,直接蒸发不见了。

why?是因为太多情,对象太多了么?

这是趣味性和技巧性非常突出的一个问题。

执行dmesg命令,大概率会看到你的进程崩溃信息躺尸在那里。

 

为了能看到发生的时间,我们习惯性加上参数T

  1. dmesg -T 

明显是操作系统看你的进程不顺眼,给Kill了。

这个现象,和Linux的内存管理有关。

由于Linux系统采用的是虚拟内存分配方式,JVM的代码,库,堆和栈的使用都会消耗内存,但是申请出来的内存,只要没真正access过,是不算的,因为没有真正为之分配物理页面。

随着使用内存越用越多。第一层防护墙就是SWAP;当SWAP也用的差不多了,会尝试释放cache;当这两者资源都耗尽,杀手就出现了。oom killer会在系统内存耗尽的情况下跳出来,选择性的干掉一些进程以求释放一点内存。

 

所以这时候我们的Java进程,是操作系统“主动”终结的,JVM连发表遗言的机会都没有。这个信息,只能在操作系统日志里找。

要解决这种问题,首先不能太贪婪。比如一共8GB的机器,你把整整7.5GB分配给了JVM。当操作系统内存不足,你的JVM就可能成为oom-killer的猎物。

不过,通过下面的命令,可以让进程避免被审判。

  1. echo -17 > /proc/[PID]/oom_adj 

这是因为,oom_adj文件,就是进程被oom killer杀掉的权重,一般介于 [-17,15]之间。越高的权重,意味着更可能被oom killer选中。

一旦你这么做,你的Java进程就是特权阶层了,可以无视规则。

2. 执行了上帝函数

xjjdog对这个函数的评价是:比你起认识它,还不如你不认识它。

这位函数你不要瞅我。说的就是你,System.exit。

这个函数危险得很,它将强制终止我们的应用,而且什么都不会留下。你应该扫描你的代码,确保这样的逻辑不会存在。

相信我,你并没有需要用程序判断来立即结束进程的需求,业务系统尤其没有。如果有,那大概率是不合理的。除非你把Java当脚本用了。

这个函数,是一个非常高级的埋坑技能,尤其是在Android之类的应用中。应用程序崩溃,你将什么原因都分析不到,哪怕你做了ShutdownHook。

使用exit函数,一定要心存善意。

当然我们并不是对此束手无策。下面这段代码,就可以阻止exit的执行,霸道非凡。上帝的那只手,也给掰回去。

  1. import java.security.Permission; 
  2.  
  3. public class S { 
  4.     private static class ExitTrappedException extends SecurityException { 
  5.     } 
  6.     private static void forbidSystemExitCall() { 
  7.         final SecurityManager securityManager = new SecurityManager() { 
  8.             public void checkPermission(Permission permission) { 
  9.                 if (permission.getName().startsWith("exitVM")) { 
  10.                     throw new ExitTrappedException(); 
  11.                 } 
  12.             } 
  13.         }; 
  14.         System.setSecurityManager(securityManager); 
  15.     } 
  16.     private static void enableSystemExitCall() { 
  17.         System.setSecurityManager(null); 
  18.     } 
  19.     public static void main(String[] args) { 
  20.         forbidSystemExitCall(); 
  21.         try { 
  22.             System.exit(0); 
  23.         }catch (Exception ex){ 
  24.             ex.printStackTrace(); 
  25.         } 
  26.         System.out.println("谢谢xjjjdog, 我依然能够执行"); 
  27.     } 

如果你用尽千方百计,都找不到异常终止的原因,试试挂上这段代码吧。有可能是救命的哦。

3. 错误的启动方式

再聊一种最初级最常见还经常发生的一种情况,会造成应用程序的意外死亡:那就是对Java程序错误的启动方式。

很多同学对Linux不是很熟悉,使用XShell登陆之后,调用下面的命令进行启动。

  1. java com.cn.AA & 

这位同学还算有点意识,在最后使用了&号,以期望进程在后台运行。但可惜的是,很多情况下,随着XShell Tab页的关闭,或者等待超时,后面的Java进程就随着一块停止了,很让人困惑。 

正确的启动方式,就是使用nohup关键字,或者阻塞在其他更加长命的进程里(比如docker)。

  1. nohup java com.cn.AA & 

所以,当你登录上终端tty的时候,一定要闹明白当前执行的父进程是谁。你可能是所有接下来要运行的所有进程的祖先哦。

4.日志配置错误

如果上面的原因都不是,那大概率是你的项目里面日志框架的配置错误了。Java中的日志框架繁多,配置方式多样,一不小心,就会踩坑。即使你用的是SpringBoot,也会因为依赖包的问题,造成启动问题。

日志配置错误+异常情况,当然是什么都不会留下。

使用下面的命令,可以将依赖树转移到log文件里进行分析。

  1. mvn dependency:tree > dep.log 

如果是SpringBoot项目,是可以给main类加点代码的。

  1. public static void main(String[] args) { 
  2.   try { 
  3.    SpringApplication.run(LinkpowerDtulockApplication.class, args); 
  4.   } catch (Exception e) { 
  5.    System.out.println(e); 
  6.   } 

这样有什么异常情况,就可以早点发现。

End另外,还有一些千奇百怪的原因。比如磁盘满了,句柄不够了,这些情况都很隐蔽,需要你精确把控系统的细节。

进程这种静悄悄的死亡方式,通常会给我们的问题排查带来更多的困难。

通常,我们在关闭服务的时候,会使用“kill -15”,而不是“kill -9”,以便让服务在临死之前喘口气。但并不总是有效,因为程序压根就没有机会发表遗言,有更高级别的存在阻止了它。Java进程横死,我们只能寻找其他手段。 

作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,进一步交流。

 

责任编辑:武晓燕 来源: 小姐姐味道
相关推荐

2011-12-22 16:22:16

收购

2018-03-27 11:37:02

iOS程序面试

2021-08-04 10:32:34

人工智能机器学习技术

2020-12-30 14:07:12

人工智能人工智能应用

2012-08-08 13:39:28

2011-06-28 13:43:50

Java EE

2009-06-15 17:05:02

IP通信

2014-12-25 19:06:13

数据泄露

2018-04-12 14:26:50

2013-08-02 09:34:11

平台即服务PaaSPaaS平台

2011-07-06 12:04:53

架构

2012-10-30 14:41:56

2012-03-28 09:48:45

2013-03-01 11:00:23

2009-11-19 11:03:51

Oracle LogM

2020-05-13 11:19:30

SaaS云计算技术

2009-03-01 21:13:27

iPhone苹果3G

2015-05-28 20:46:06

2018-05-09 11:06:56

云计算边缘计算雾计算

2019-05-05 09:46:01

Python代码神经网络
点赞
收藏

51CTO技术栈公众号