老板:kill -9的原理都不知道就敢到线上执行,明天不用来了-程序员宅基地

技术标签: jvm  java  linux  编程语言  多线程  

点击上方蓝色“方志朋”,选择“设为星标”

回复“666”获取独家整理的学习资料!

这是Hollis的第 270篇原创分享

作者 l Hollis

来源 l Hollis(ID:hollischuang)

相信很多程序员对于Linux系统都不陌生,即使自己的日常开发机器不是Linux,那么线上服务器也大部分都是的,所以,掌握常用的Linux命令也是程序员必备的技能。

但是,怕就怕很多人对于部分命令只是一知半解,使用不当就能导致线上故障。

前段时间,我们的线上应用报警,频繁FGC,需要紧急处理问题,于是有同事去线上重启机器(正常程序应该是先采集堆dump,然后再重启,方便排查是否存在内存泄露等问题)。

但是在重启过程中,同事发现正常的重启命令应用无反应,然后尝试使用kill命令"杀"掉Java进程,但是仍然无效。于是他私自决定使用 "kill -9"结束了进程的生命。

虽然应用进程被干掉了,但是随之而来带来了很多问题,首先是上游系统突然发生大量报警,对应开发找过来说调用我们的RPC服务无响应,频繁超时。

后来,我们又发现系统中存在部分脏数据,有些在同一个事务中需要完整更新的数据,只更新了一半…

为什么正常的kill无法"杀掉"进程,而kill -9就可以?为什么kill -9会引发这一连串连锁反应?正常的kill执行时,JVM会如何处理的呢?

要搞清楚这些问题,我们要先从kill命令说起。

kill 命令

我们都知道,想要在Linux中终止一个进程有两种方式,如果是前台进程可以使用Ctrl+C键进行终止;如果是后台进程,那么需要使用kill命令来终止。(其实Ctrl+C也是kill命令)

kill命令的格式是:

kill[参数][进程号]

如:

kill 21121

kill -9 21121

其中[参数]是可选的,进程号可以通过jps/ps/pidof/pstree/top等工具获取。

kill的命令参数有以下几种:

-l 信号,若果不加信号的编号参数,则使用“-l”参数会列出全部的信号名称

-a 当处理当前进程时,不限制命令名和进程号的对应关系

-p 指定kill 命令只打印相关进程的进程号,而不发送任何信号

-s 指定发送信号

-u 指定用户

通常情况下,我们使用的-l(信号)的时候比较多,如我们前文提到的kill -9中的9就是信号。

信号如果没有指定的话,默认会发出终止信号(15)。常用的信号如下:

HUP 1 终端断线

INT 2 中断(同 Ctrl + C)

QUIT 3 退出(同 Ctrl + \)

TERM 15 终止

KILL 9 强制终止

CONT 18 继续(与STOP相反, fg/bg命令)

STOP 19 暂停(同 Ctrl + Z)

比较常用的就是强制终止信号:9终止信号:15,另外,中断信号:2其实就是我们前文提到的Ctrl + C结束前台进程。

那么,kill -9kill -15到底有什么区别呢?该如何选择呢?

kill -9 和 kill -15的区别

kill命令默认的信号就是15,首先来说一下这个默认的kill -15信号。

当使用kill -15时,系统会发送一个SIGTERM的信号给对应的程序。当程序接收到该信号后,具体要如何处理是自己可以决定的。

这时候,应用程序可以选择:

  • 1、立即停止程序

  • 2、释放响应资源后停止程序

  • 3、忽略该信号,继续执行程序

因为kill -15信号只是通知对应的进程要进行"安全、干净的退出",程序接到信号之后,退出前一般会进行一些"准备工作",如资源释放、临时文件清理等等,如果准备工作做完了,再进行程序的终止。

但是,如果在"准备工作"进行过程中,遇到阻塞或者其他问题导致无法成功,那么应用程序可以选择忽略该终止信号。

这也就是为什么我们有的时候使用kill命令是没办法"杀死"应用的原因,因为默认的kill信号是SIGTERM(15),而SIGTERM(15)的信号是可以被阻塞和忽略的。

kill -15相比,kill -9就相对强硬一点,系统会发出SIGKILL信号,他要求接收到该信号的程序应该立即结束运行,不能被阻塞或者忽略。

所以,相比于kill -15命令,kill -9在执行时,应用程序是没有时间进行"准备工作"的,所以这通常会带来一些副作用,数据丢失或者终端无法恢复到正常状态等。

Java是如何处理SIGTERM(15)的

我们都知道,在Linux中,Java应用是作为一个独立进程运行的,Java程序的终止运行是基于JVM的关闭实现的,JVM关闭方式分为3种:

正常关闭:当最后一个非守护线程结束或者调用了System.exit或者通过其他特定平台的方法关闭(接收到SIGINT(2)、SIGTERM(15)信号等)

强制关闭:通过调用Runtime.halt方法或者是在操作系统中强制kill(接收到SIGKILL(9)信号)

异常关闭:运行中遇到RuntimeException异常等。

JVM进程在接收到kill -15信号通知的时候,是可以做一些清理动作的,比如删除临时文件等。

当然,开发者也是可以自定义做一些额外的事情的,比如让tomcat容器停止,让dubbo服务下线等。

而这种自定义JVM清理动作的方式,是通过JDK中提供的shutdown hook实现的。JDK提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子。

例子如下:

package com.hollis;


public class ShutdownHookTest {


    public static void main(String[] args) {

        boolean flag = true;

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {

            System.out.println("hook execute...");

        }));


        while (flag) {

            // app is runing

        }


        System.out.println("main thread execute end...");

    }

}

执行命令:

➜ jps

6520 ShutdownHookTest

6521 Jps

➜ kill 6520

控制台输出内容:

hook execute...

Process finished with exit code 143 (interrupted by signal 15: SIGTERM)

可以看到,当我们使用kill(默认kill -15)关闭进程的时候,程序会先执行我注册的shutdownHook,然后再退出,并且会给出一个提示:interrupted by signal 15: SIGTERM

如果我们执行命令kill -9

➜ kill -9 6520

控制台输出内容:

Process finished with exit code 137 (interrupted by signal 9: SIGKILL)

可以看到,当我们使用kill -9 强制关闭进程的时候,程序并没有执行shutdownHook,而是直接退出了,并且会给出一个提示:interrupted by signal 9: SIGKILL

总结

kill命令用于终止Linux进程,默认情况下,如果不指定信号,kill 等价于kill -15

kill -15执行时,系统向对应的程序发送SIGTERM(15)信号,该信号是可以被执行、阻塞和忽略的,所以应用程序接收到信号后,可以做一些准备工作,再进行程序终止。

有的时候,kill -15无法终止程序,因为他可能被忽略,这时候可以使用kill -9,系统会发出SIGKILL(9)信号,该信号不允许忽略和阻塞,所以应用程序会立即终止。

这也会带来很多副作用,如数据丢失等,所以,在非必要时,不要使用kill -9命令,尤其是那些web应用、提供RPC服务、执行定时任务、包含长事务等应用中,因为kill -9 没给spring容器、tomcat服务器、dubbo服务、流程引擎、状态机等足够的时间进行收尾。

热门内容:

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・。)ノ♡
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhipengfang/article/details/117454446

智能推荐

(附源码)ssm基于微信小程序的社区老人健康管理服务系统的设计与实现 毕业设计011513_基于微信小程序的社区管理系统设计论文-程序员宅基地

文章浏览阅读2k次,点赞7次,收藏30次。对于本社区老人健康管理服务系统的设计来说,通过科学的管理方式、便捷的服务提高了工作效率,减少了数据存储上的错误和遗漏。社区老人健康管理服务系统使用Java语言,采用基于MVVM模式的SSM技术进行开发,使用 Eclipse 2017 CI 10 编译器编写,数据方面主要采用的是微软的MySQL关系型数据库来作为数据存储媒介,配合前台HTML+CSS 技术完成系统的开发。具体根据社区老人健康管理服务系统的现状来进行开发的,具体根据用户需求实现社区老人健康管理服务系统网络化的管理,各类信息有序地进行存储...._基于微信小程序的社区管理系统设计论文

Java中的Action、Service和DAO层功能区分及示例解释-程序员宅基地

文章浏览阅读555次。Action/Service/DAO简介:Action是管理业务(Service)调度和管理跳转的。Service是管理具体的功能的。Action只负责管理,而Service负责实施。DAO只完成增删改查,虽然可以1-n,n-n,1-1关联,模糊、动态、子查询都可以。但是无论多么复杂的查询,dao只是封装增删改查。至于增删查改如何去实现一个功能,dao是不管的。总结这三者,通过例子来解释:Acti..._java中action

Servlet详解-程序员宅基地

文章浏览阅读321次。Servlet (Server Applet),全称Java Servlet。是用Java编写的服务器端程序,其,生成动态的Web内容。Servlet运行于支持Java的应用服务器中(如Tomcat等)。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下,servlet只用来扩展基于HTTP协议的服务器。

VMware与艾莫讯国产300编程电缆兼容性问题_虚拟机插入mpi电缆卡死-程序员宅基地

文章浏览阅读1.3k次。VMware-15.1.0 -VMware-15.5.5之间所有的版本都与国产艾莫讯0CB20电缆有兼容问题。 具体故障是只要连接到虚拟机并驱动就会造成虚拟机死机。西门子官方的0CB20电缆不会存在这个问题。说明国产电缆和官方电缆的实现方式还是有区别,这次蓝屏死机BUG主要是由VMware引起的,为了验证我还特意去咸鱼上整了一条官方电缆。 我为什么知道这么清楚呢,因为vmware每一次更新我都会去升级,然后去现场干活。接下来的事情你们应该能想到了,去现场都读程序,结果插上电缆就死机。急忙跟客户说.._虚拟机插入mpi电缆卡死

java找不到符号解决办法-程序员宅基地

文章浏览阅读1.6w次,点赞11次,收藏15次。一、java找不到符号如果你的代码里没有报错,明明是存在的。但是java报错找不到符号。像下面这样子。二、解决步骤1.清除编码工具缓存本人用的idea, eclipse清除缓存方式有需要的可以百度一下!2.如果是mavne项目的先clean 再package总结提示:一定要package本人刚开始就是知道clean了,没有package导致问题一直没有解决。在此记录一下!...

【Nginx】配置详解_nginx修改配置文件如何生效-程序员宅基地

文章浏览阅读1.3w次,点赞4次,收藏22次。访问到未定义的扩展名的时候,就默认为下载该文件。#服务器并发处理能力,值越大并发能力越强(受自身配置限制)一个http块可以包含多个server块,而一个server块就等于一个虚拟主机。nginx配置最频繁的部分,比如代理,日志,缓存、第三方模块等等。包括文件引入、MIME-TYPE定义,日志自定义、连接超时等等。需要注意的是http块可以包括http全局块和server块。server块又包含全局server块和location块。二、容器部署的项目,配置nginx。2.2,events块。..._nginx修改配置文件如何生效

随便推点

Buck电路 (PWM实现与闭环反馈) 电力系统仿真_buck电路带反馈控制-程序员宅基地

文章浏览阅读962次,点赞2次,收藏11次。Buck电路 (PWM实现与闭环反馈) 电力系统仿真_buck电路带反馈控制

jQuery实现轮播图代码_jquery轮播图代码-程序员宅基地

文章浏览阅读699次,点赞11次,收藏8次。一个简单的jQuery轮播图代码,首先,定义了一个slideshow-container的div容器,其中包含了所有轮播图幻灯片。每个幻灯片都包含一个mySlides的类名,并且使用CSS将其隐藏。在showSlides()函数中,遍历所有幻灯片并将它们隐藏,然后显示当前索引的幻灯片。最后,我们使用setTimeout()函数来每隔2秒钟调用showSlides()函数,从而实现了轮播效果。它使事情变得更简单,使用jQuery能够以最小的努力在Web上构建复杂的交互性。_jquery轮播图代码

android adb install apk的安装流程_full install must include a base packag-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏23次。一、简介 1.Android上应用安装可以分为以下几种方式:通过adb命令安装:adb 命令包括adb push/install 用户下载的Apk,通过系统安装器packageinstaller安装该Apk。packageinstaller是系统内置的应用程序,用于安装和卸载应用程序。 系统开机时安装系统应用。 电脑或者手机上的应用商店自动安装第三种系统安装我们在上个章节P..._full install must include a base packag

漂亮的css透明样式菜单-程序员宅基地

文章浏览阅读74次。下载地址漂亮的css透明样式菜单,可以用作工具栏或者导航条,小图标可以自定义。dd:_漂亮的css透明样式菜单

牛人莫入 Silverlight DataGrid 分组技巧 -程序员宅基地

文章浏览阅读983次。牛人莫入 Silverlight DataGrid 分组技巧 最近在项目中很多的地方都用到了数据的展示---DataGrid控件,在园子里面也有很多的朋友也对这个DataGrid控件也写了很多的教程;我这里也与其它人也没有什么区别,这里只是告诉大家一个小的技巧;但是我相信这一个小的技巧对大家以后在项目中应该有一些帮助;一天,领导走过来看了我用户管理UI,我用了一

U-net网络_sr3 的u-net-程序员宅基地

文章浏览阅读1.8w次,点赞14次,收藏89次。 U-net网络是一个典型的端到端的网络结构。如下图所示: 基本的网络结构并不复杂,但是代码实现过程中需要进行调试,但这会花费很大的时间。本文旨在为初学者介绍代码的快速使用方法,直接将U-net网络作为黑盒使用。如果您觉得对您有用,请点个赞,欢迎交流。一:从github上下载改进的U-net源码:点击打开传送门显示如下:二:点击Clone or download,下载..._sr3 的u-net