欢迎光临
我们一直在努力

# Linux 进程管理:程序在 Linux 中是如何运行的? 在 Linux 中,我们执行一个 Java 程序、启动一个 MySQL 服务,或者运行一个 Python 脚本,本质上都是在系统中创建

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

在 Linux 中,我们执行一个 Java 程序、启动一个 MySQL 服务,或者运行一个 Python 脚本,本质上都是在系统中创建并运行进程。

例如,当我们启动 Spring Boot 项目时,Linux 会为它分配进程 ID(PID),并由操作系统负责调度 CPU、分配内存以及管理进程的运行状态。

如果服务器出现 CPU 占用过高、Java 服务无响应、程序意外退出等问题,就需要使用 Linux 的进程管理命令进行排查。

1. 什么是进程?

进程(Process)是程序的一次运行实例,是操作系统进行资源分配和管理的重要单位。

例如,我们编写了一个 Java 程序:

public class Main {
public static void main(String[] args) {
while (true) {
System.out.println("Hello Linux");
}
}
}

当我们执行这个程序时,操作系统会创建一个进程,为其分配运行所需的资源,例如内存、文件描述符等。

这里需要区分两个概念:

  • 程序(Program):存储在磁盘上的可执行代码,是一个静态概念。
  • 进程(Process):程序运行时产生的实例,是一个动态概念。

一个程序可以被多次启动,从而产生多个不同的进程。

进程的基本属性

每个进程都有自己的标识和运行信息,常见的有:

属性含义
PID Process ID,进程 ID,用于唯一标识当前进程
PPID Parent Process ID,父进程 ID
UID 进程所属用户的 ID
GID 进程所属用户组的 ID
状态 表示进程当前的运行状态
CPU 进程占用的 CPU 资源
内存 进程使用的内存资源

其中,PID 是我们后续管理进程时最常用的信息。

2. 如何查看 Linux 中的进程?

Linux 提供了很多进程查看命令,最常用的是 ps 和 top。

2.1 ps:查看当前进程信息

ps(Process Status)用于查看进程信息。

# 查看当前终端关联的进程
ps

# 查看系统中所有进程的详细信息
ps -ef

# 查看系统中所有进程的资源使用情况
ps aux

其中,ps -ef 和 ps aux 是最常见的两种用法。

ps -ef:

ps -ef

输出示例:

UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Nov05 ? 00:00:02 /sbin/init
app 1024 1 2 Nov05 ? 00:01:20 java -jar app.jar

常见字段:

字段含义
UID 进程所属用户
PID 当前进程 ID
PPID 父进程 ID
C CPU 使用情况的调度相关指标
STIME 进程启动时间
TTY 关联的终端
TIME 累计使用的 CPU 时间
CMD 启动进程的命令

ps aux:

ps aux

常见字段:

字段含义
USER 进程所属用户
PID 进程 ID
%CPU CPU 使用率
%MEM 内存使用率
VSZ 虚拟内存大小
RSS 常驻物理内存大小
STAT 进程状态
START 进程启动时间
COMMAND 启动命令

例如,想查看 Java 进程:

ps -ef | grep java

这样就可以从所有进程中筛选出包含 java 的进程。

需要注意,grep java 本身也可能出现在结果中,可以使用:

ps -ef | grep '[j]ava'

2.2 top:实时查看进程状态

top 用于动态显示系统和进程的资源使用情况。

top

与 ps 不同,top 会持续刷新数据,方便我们观察系统运行状态。

进入 top 后,可以看到:

  • CPU 使用率。
  • 内存使用情况。
  • 系统负载(Load Average)。
  • 当前运行的进程数量。
  • 每个进程的 CPU 和内存占用。

常用快捷键:

按键作用
P 按 CPU 使用率排序
M 按内存使用率排序
1 展开显示各个 CPU 核心的使用情况
k 向指定 PID 发送信号
q 退出

例如,服务器 CPU 占用突然升高,我们可以执行 top,然后按 P,查看哪些进程占用了大量 CPU。

2.3 ps 和 top 有什么区别?

对比pstop
数据展示 一次性快照 动态刷新
使用方式 执行命令后输出结果 进入交互界面
适用场景 查询进程 PID、PPID 等信息 实时监控 CPU、内存
数据变化 不会自动刷新 持续刷新

简单来说:ps 用于查询某一时刻的进程信息,top 用于实时监控进程运行情况。

3. 如何根据 PID 查找进程?

除了使用 ps,我们还可以使用 pgrep 根据进程名称查找 PID。

# 查找名称包含 java 的进程
pgrep java

# 同时显示 PID 和进程名称
pgrep -a java

如果想查看某个进程的详细信息:

ps -p 1024 -f

其中 -p 用于指定 PID。

还可以通过 pstree 查看进程之间的父子关系:

pstree -p

例如,Linux 启动过程中会形成进程之间的父子关系,通过进程树可以更直观地观察这些关系。

4. 如何终止一个进程?kill 命令

当某个程序出现异常,或者我们需要停止一个服务时,可以使用 kill 命令。

kill PID

例如:

kill 1024

这里需要注意:kill 并不意味着一定是强制杀死进程,它的本质是向指定进程发送信号(Signal)。

Linux 提供了多种信号,不同信号代表不同的控制行为。

常见信号

信号编号含义
SIGHUP 1 终端挂断信号,也常被部分程序用于重新加载配置
SIGINT 2 中断信号,通常由 Ctrl+C 产生
SIGKILL 9 强制终止进程,不能被捕获或忽略
SIGTERM 15 请求进程正常终止
SIGSTOP 19(常见 Linux 架构) 暂停进程,不能被捕获或忽略
SIGCONT 18(常见 Linux 架构) 恢复暂停的进程

其中最常用的是 SIGTERM 和 SIGKILL。

第一种:正常终止

kill -15 1024

也可以直接使用:

kill 1024

因为 kill 默认发送 SIGTERM 信号。

SIGTERM 表示请求进程正常退出,程序可以捕获这个信号,并执行清理工作,例如关闭数据库连接、释放资源、保存数据等。

第二种:强制终止

kill -9 1024

SIGKILL 会强制终止进程,进程无法捕获、忽略或处理这个信号,因此也无法执行自己的正常清理逻辑。

通常建议:

  • 先使用 kill PID 请求程序正常退出。
  • 等待一段时间,检查进程是否已经结束。
  • 如果进程仍然无法退出,再考虑使用 kill -9 PID。
  • 不要一遇到问题就直接使用 kill -9,否则可能导致资源没有正常释放,或者业务数据处于不一致状态。

    5. 前台进程和后台进程

    在 Linux 中,我们启动程序时,通常会遇到两种运行方式:前台运行和后台运行。

    5.1 前台进程

    直接执行命令:

    ping www.baidu.com

    程序会持续输出结果,并占用当前终端。

    在程序运行期间,我们不能直接在当前终端输入其他命令,除非暂停或终止当前任务。

    这种方式称为前台运行。

    5.2 后台进程

    如果希望程序在后台运行,可以在命令末尾添加 &:

    ping www.baidu.com &

    此时程序会在后台运行,终端可以继续执行其他命令。

    例如:

    java -jar app.jar &

    这样 Spring Boot 程序就会在后台运行。

    不过要注意:使用 & 只是让进程在后台运行,并不保证关闭终端后进程仍然存活。

    6. jobs、bg、fg:管理当前终端的任务

    Linux 提供了几个命令,用于管理当前 Shell 中的后台任务。

    6.1 jobs:查看当前 Shell 的后台任务

    jobs

    例如:

    [1]+ Running ping www.baidu.com &
    [2]- Stopped vim test.txt

    其中:

    • [1]、[2] 是任务编号(Job ID)。
    • Running 表示正在运行。
    • Stopped 表示任务已暂停。

    注意:jobs 只能查看当前 Shell 管理的任务,并不是系统中所有后台进程。

    6.2 Ctrl+Z:暂停当前前台任务

    如果一个程序正在前台运行,可以按:

    Ctrl + Z

    这会向前台进程组发送 SIGTSTP 信号,通常使当前任务暂停。

    6.3 bg:让暂停的任务在后台继续运行

    例如,先使用 Ctrl+Z 暂停任务,然后执行:

    bg

    就可以让最近暂停的任务在后台继续运行。

    也可以指定任务编号:

    bg %1

    6.4 fg:将后台任务切换到前台

    如果想让后台任务重新回到前台,可以使用:

    fg

    或者:

    fg %1

    简单总结:

    命令作用
    jobs 查看当前 Shell 的任务
    Ctrl+Z 暂停当前前台任务
    bg 让暂停任务在后台继续运行
    fg 将后台任务切换到前台

    7. 如何让程序在终端关闭后继续运行?

    前面我们介绍了使用 & 将程序放到后台,但它仍然可能受到终端退出的影响。

    例如:

    java -jar app.jar &

    如果关闭终端,Shell 退出时可能会向相关进程发送 SIGHUP,导致程序终止。

    如果希望程序在终端关闭后继续运行,可以使用 nohup。

    7.1 nohup:忽略终端挂断信号

    nohup java -jar app.jar &

    其中:

    • nohup:让命令忽略 SIGHUP 信号。
    • &:让命令在后台运行。

    默认情况下,程序的输出会写入当前目录下的 nohup.out 文件(前提是标准输出未被重定向)。

    更推荐在实际部署时指定日志文件:

    nohup java -jar app.jar > app.log 2>&1 &

    这里有几个重要知识点:

    符号作用
    > 将标准输出重定向到文件
    2> 将标准错误重定向到文件
    2>&1 将标准错误重定向到标准输出当前指向的位置
    & 让命令在后台运行

    因此:

    nohup java -jar app.jar > app.log 2>&1 &

    表示:

  • 使用 nohup 忽略终端挂断信号。
  • 将标准输出写入 app.log。
  • 将标准错误也写入 app.log。
  • 将程序放到后台运行。
  • 7.2 如何查看后台 Java 服务?

    # 查看 Java 进程
    ps -ef | grep '[j]ava'

    # 实时查看日志
    tail -f app.log

    # 停止程序
    kill PID

    不过,nohup 适合简单的后台运行场景。生产环境中,更推荐使用 systemd 管理服务,这样可以统一管理服务的启动、停止、重启、开机自启和日志。

    8. 进程和线程有什么区别?

    这部分与我们之前学习的 JVM 和 Java 多线程知识有关。

    进程是资源分配和管理的重要单位,线程是 CPU 调度的基本单位。

    一个进程可以包含多个线程,这些线程共享进程的大部分资源,例如进程地址空间和打开的文件等。

    例如,一个 Spring Boot 应用启动后,Linux 会创建对应的 Java 进程,而 JVM 内部还会创建多个线程,用于处理请求、执行任务、进行垃圾回收等。

    可以通过下面的命令查看某个进程中的线程:

    # 查看指定进程中的线程
    ps -T -p 1024

    也可以使用:

    top -H -p 1024

    其中:

    • -T:显示指定进程中的线程。
    • -H:在 top 中显示线程。

    注意:Linux 内核中线程也有自己的任务标识(TID),但它们属于同一个线程组,共享进程的大部分资源。

    9. 实战:排查 Spring Boot 服务进程

    假设我们在 Linux 服务器上部署了一个 Spring Boot 项目,启动命令如下:

    nohup java -jar app.jar > app.log 2>&1 &

    现在我们需要检查服务是否正常运行。

    第一步:查找 Java 进程

    ps -ef | grep '[j]ava'

    第二步:查看 CPU 和内存占用

    top

    按 P 可以按照 CPU 使用率排序,按 M 可以按照内存使用率排序。

    第三步:查看程序日志

    tail -f app.log

    第四步:查看进程中的线程

    假设 Java 进程 PID 为 1024:

    ps -T -p 1024

    第五步:停止服务

    kill 1024

    如果程序没有正常退出,再根据实际情况考虑:

    kill -9 1024

    通过这些命令,我们就可以完成 Java 服务的基本进程排查和管理。

    10. 总结

    Linux 中常见的进程管理知识:

    命令作用
    ps 查看进程信息
    top 实时监控系统和进程
    pgrep 根据进程名称查找 PID
    pstree 查看进程树
    kill 向进程发送信号
    jobs 查看当前 Shell 的后台任务
    bg 让暂停任务在后台运行
    fg 将后台任务切换到前台
    nohup 忽略 SIGHUP 信号运行程序
    & 让命令在后台运行

    对于后端开发来说,进程管理是 Linux 非常重要的一部分。无论是部署 Java 服务、排查 CPU 占用过高,还是处理程序异常退出,都离不开这些命令。

    赞(0)
    未经允许不得转载:171主机测评 » # Linux 进程管理:程序在 Linux 中是如何运行的? 在 Linux 中,我们执行一个 Java 程序、启动一个 MySQL 服务,或者运行一个 Python 脚本,本质上都是在系统中创建
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址