文章

操作系统高频总结六

top命令排查高占有率进程/top命令的占用率怎么算的

1. 使用 top 命令排查高占用率进程

top 是 Linux 系统中一个强大的工具,用于实时监控系统的资源使用情况(CPU、内存等)以及各个进程的详细信息。以下是如何使用 top 排查高占用率进程的详细步骤。


1.1 启动 top 命令

在终端中输入:

1
top

1.2 默认界面

top 的默认界面包括以下几个部分:

  • 系统总体信息(顶部几行):

    • Tasks:任务和线程的总数、运行数、睡眠数等。
    • CPU 使用率:分用户态(us)、系统态(sy)、空闲(id)等详细信息。
    • 内存和交换分区使用情况
  • 进程列表(底部部分): 每个进程的一行信息,包括以下字段:

    字段含义
    PID进程 ID
    USER所属用户
    %CPUCPU 占用率
    %MEM内存占用率
    COMMAND进程名称或命令

1.3 查找高占用率进程

(1) 按 CPU 占用率排序

默认情况下,top 按 CPU 占用率排序。可以按以下键进行操作:

  • P:按 CPU 使用率排序。
  • M:按内存使用率排序。
  • T:按运行时间排序。
(2) 手动搜索进程

/ 键,输入进程名或关键字进行搜索。

(3) 监控特定进程

Shift + p 按键过滤并实时监控。


1.4 查杀高占用率的进程

找到占用率高的进程后,可以通过以下方式结束进程:

  1. 记下进程的 PID
  2. k 键,输入 PID。
  3. 确认后发送信号(默认是 SIGTERM)。

或者直接在终端中使用 kill 命令:

1
kill -9 <PID>

2. top 中占用率的计算方法

2.1 CPU 占用率(%CPU)

%CPU 表示进程消耗的 CPU 时间占总 CPU 时间的比例。计算公式为:

$\text{CPU占用率} = \frac{\text{进程消耗的CPU时间}}{\text{系统运行的总时间}} \times 100\%$

详细说明

  • 进程消耗的 CPU 时间:某一进程消耗的用户态(user)和系统态(sys)时间。
  • 系统运行的总时间:系统总共运行的时间(所有 CPU 核心的总时间)。

多核系统中%CPU 的总值可以超过 100%。 例如:在 4 核系统中,如果一个进程使用了所有 4 核的 100% 资源,其 CPU 占用率可以显示为 400%。


2.2 内存占用率(%MEM)

%MEM 表示进程使用的内存占系统总内存的比例。计算公式为:

$\text{内存占用率} = \frac{\text{进程使用的内存(RES)}}{\text{系统总内存}} \times 100\%$

  • RES:进程实际使用的物理内存大小(不包括交换空间)。
  • 系统总内存:物理内存的总量。

2.3 load average 的含义

top 界面顶部显示的 load average 值表示系统的平均负载。它是一定时间内(1 分钟、5 分钟、15 分钟)的平均运行队列长度,包含以下内容:

  1. 正在使用 CPU 的进程。
  2. 等待使用 CPU 的进程。

解释:

  • 如果 load average 小于等于系统 CPU 核心数,系统通常处于健康状态。
  • 如果 load average 大大超过核心数,系统可能过载。

3. 实用的 top 命令技巧

3.1 显示特定用户的进程

u 键,然后输入用户名,过滤显示该用户的所有进程。

3.2 只显示指定 PID 的进程

1
top -p <PID>

3.3 自动刷新间隔

默认刷新间隔为 3 秒,可以通过以下命令调整:

  • 在运行时按 d,然后输入秒数。

  • 启动时指定:

    1
    
    top -d 2
    

3.4 输出到文件

可以将 top 的输出写入文件,便于分析:

1
top -b -n 1 > top_output.txt
  • -b:以批处理模式运行。
  • -n 1:刷新一次后退出。

4. 总结

  • 排查高占用率进程: 使用 topPM 键分别查看 CPU 或内存的占用率,结合 k 键或 kill 命令结束异常进程。
  • 占用率计算
    • %CPU:表示进程使用 CPU 的时间比例,多核系统中可能超过 100%。
    • %MEM:表示进程使用物理内存的比例。

熟练掌握 top 命令及其参数,可以高效地监控和排查系统性能问题。

谈谈进程创建后在Linux中的内存分布?

在 Linux 中,当一个进程被创建后,其内存分布是按照 虚拟内存地址空间 的组织方式来划分的。这种分布决定了进程各部分的存储位置、访问权限以及功能。以下是 Linux 进程创建后内存分布的详细解析:


1. 进程内存分布概览

Linux 的进程虚拟地址空间通常分为以下几个区域,从低地址到高地址:

区域主要内容
NULL 段不可访问的内存区域,用于检测空指针访问。
代码段(Text Segment)存放程序的可执行代码(只读,静态内容)。
数据段(Data Segment)存放全局变量和静态变量,分为已初始化和未初始化(.data.bss)。
堆(Heap)动态分配的内存(如 mallocnew 分配的内存)。
映射段(Mapped Segment)包括动态库和内存映射文件(如 mmap 加载的文件)。
栈(Stack)函数调用的局部变量、返回地址、函数参数等,向低地址方向增长。

2. 各内存区域的详细说明

2.1 NULL 段

  • 地址范围:0x0 或非常靠近 0x0
  • 作用:
    • 空指针的默认值。
    • 访问此区域会导致 段错误(Segmentation Fault)

2.2 代码段(Text Segment)

  • 存储内容:
    • 程序的机器指令(可执行代码)。
    • 常量字符串(例如 const char* 声明的字符串)。
  • 特点:
    • 只读区域,防止代码被意外修改。
    • 多个进程可以共享代码段(例如动态库的代码段)。
  • 地址范围:
    • 进程启动后固定,通常由 ELF 文件格式决定。

2.3 数据段(Data Segment)

数据段包含全局变量和静态变量,分为两部分:

  1. 已初始化数据段(.data)

    • 存放已初始化的全局变量和静态变量。

    • 例如:

      1
      
      int a = 10; // 存放在 .data 段
      
    • 程序加载时直接初始化。

  2. 未初始化数据段(.bss)

    • 存放未初始化的全局变量和静态变量。

    • 系统在程序启动时自动将这些变量初始化为 0

    • 例如:

      1
      
      int b; // 存放在 .bss 段
      

2.4 堆(Heap)

  • 存储内容:
    • 动态分配的内存(malloccallocreallocnew)。
  • 特点:
    • 向高地址方向增长。
    • 由内核通过 brkmmap 系统调用管理。
    • 堆大小可以在程序运行时动态扩展或收缩。
  • 常见问题:
    • 内存泄漏:未释放的动态内存。
    • 悬挂指针:已释放内存的指针被继续使用。

2.5 映射段(Mapped Segment)

  • 存储内容:

    • 动态库(如 .so 文件)和内存映射文件。
  • 特点:

    • 动态库的代码段和只读数据段通常可被多个进程共享。
    • 使用 mmap 系统调用加载的文件会占用此区域。
    • 地址分布通常由加载器决定,位置不固定。
  • 示例: 动态库的加载地址可以通过以下命令查看:

    1
    
    cat /proc/<PID>/maps
    

2.6 栈(Stack)

  • 存储内容:

    • 函数调用帧,包括局部变量、返回地址、参数等。
  • 特点:

    • 向低地址方向增长。

    • 每个线程有自己独立的栈。

    • 栈大小受限,可以通过

      1
      
      ulimit
      

      查看或修改:

      1
      
      ulimit -s
      
    • 默认栈大小通常是几 MB。

  • 常见问题:

    • 栈溢出:递归调用过深或局部变量占用过多内存。

3. 进程的虚拟地址分布示例

假设一个 64 位进程的虚拟地址空间分布如下:

1
2
3
4
5
6
0x00000000  -  NULL 段
0x00400000  -  代码段(Text Segment)
0x00600000  -  数据段(Data Segment)
0x10000000  -  堆(Heap)
0x7f000000  -  动态库和映射段(Mapped Segment)
0x7fffffff  -  栈顶

4. 内存分布的动态调整

4.1 堆的动态增长

堆通过 brkmmap 系统调用进行增长:

1
void* ptr = malloc(1024); // 向堆申请 1024 字节内存

4.2 栈的动态调整

栈的增长是由硬件和操作系统限制的:

  • 如果栈溢出,会触发 段错误(Segmentation Fault)

  • 可以通过调整

    1
    
    ulimit
    

    修改栈大小:

    1
    
    ulimit -s 8192  # 设置栈大小为 8 MB
    

5. 调试进程的内存分布

5.1 使用 pmap 查看内存分布

1
pmap <PID>

输出示例:

1
2
3
4
Address           Kbytes     RSS   Dirty   Mode  Mapping
00400000            132       12       0  r-x--  /usr/bin/cat
0061D000              4        4       0  r----  /usr/bin/cat
...

5.2 使用 /proc/<PID>/maps

1
cat /proc/<PID>/maps

输出示例:

1
2
3
00400000-0040b000 r-xp 00000000 08:01 123456 /bin/ls
0060b000-0060c000 r--p 0000b000 08:01 123456 /bin/ls
...

5.3 使用 valgrind 检查内存问题

1
valgrind ./a.out

可以检测内存泄漏和未初始化的内存使用。


6. 总结

  • Linux 进程的虚拟地址空间是分段管理的,包括代码段、数据段、堆、栈等区域。
  • 不同区域有不同的增长方向和管理方式:
    • :动态向高地址增长。
    • :动态向低地址增长。
  • 可以使用工具如 pmap/proc/<PID>/maps 来调试和分析进程的内存分布。

在Linux系统下,使用for循环,一直进行new操作,会发生heap-overflow吗?如果不会,原因呢?

在 Linux 系统下,如果在一个 for 循环中不断进行 new 操作,不会直接导致 heap overflow(堆溢出),但可能会触发其他问题,例如内存耗尽(Out of Memory, OOM)。以下是详细分析原因及可能的后果:


1. 为什么不会直接发生 Heap Overflow?

在现代操作系统(如 Linux)中,堆内存的分配和管理由操作系统的虚拟内存管理机制和 C++ 的运行时库(如 glibc)共同完成,具有以下特点:

1.1 动态增长的堆区域

  • 堆的初始大小:当进程启动时,堆的初始大小由操作系统根据需要分配,通常很小。
  • 堆的动态增长:
    • 堆内存的增长通过系统调用(如 brkmmap)动态向高地址扩展。
    • 每次 new 操作分配内存时,如果堆空间不足,运行时库会向操作系统申请更多的内存,扩大堆的大小。

1.2 虚拟内存的保护

  • Linux 使用虚拟内存管理机制,理论上一个 64 位进程的虚拟地址空间非常大(通常上限为几百 TB),因此不会轻易发生物理地址空间的堆溢出。

2. 为什么可能发生内存耗尽(OOM)?

虽然堆不会直接溢出,但以下情况可能导致内存耗尽:

2.1 内存的物理限制

  • 物理内存(RAM)和交换空间(Swap)有限:
    • 虽然堆可以动态增长,但总内存(RAM + Swap)是有限的。
    • 如果循环中分配的内存持续增长并超过总内存,操作系统可能会触发 OOM(Out of Memory)机制,终止进程。

2.2 内存泄漏

  • 如果循环中分配的内存没有释放,未被使用的内存会累积,最终耗尽所有可用内存。

  • 示例:

    1
    2
    3
    
    while (true) {
        int* ptr = new int[1000]; // 没有释放
    }
    
    • 这里每次分配的内存都没有释放,导致堆持续增长,直到 OOM。

2.3 系统限制

  • 操作系统可能对单个进程的内存使用设置限制(例如 ulimit 设置堆大小)。

  • 可以通过以下命令查看或调整:

    1
    
    ulimit -a
    

3. 堆管理的具体机制

3.1 brkmmap

  • 小块内存分配:通常通过 brk 系统调用分配,扩展堆顶。
  • 大块内存分配:当分配的内存超过一定阈值时(如 128 KB),会使用 mmap 分配独立的内存映射区域。

3.2 内存释放

  • C++ 的 deletedelete[] 会释放内存,通知运行时库可以回收资源。
  • 运行时库管理内存池,已释放的内存可能会被重复利用,而不会立即归还给操作系统。

4. 代码分析:会不会发生问题?

示例代码

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

int main() {
    for (int i = 0; ; i++) {
        int* ptr = new int[1000]; // 每次分配 1000 个 int
        if (i % 100000 == 0) {
            std::cout << "Iteration: " << i << std::endl;
        }
    }
    return 0;
}

分析

  1. 不会发生 Heap Overflow

    • 运行时库会动态扩展堆区域,并使用虚拟内存支持更大的地址空间。
    • 物理限制被虚拟内存隐藏,操作系统会分配更多物理内存或使用交换空间。
  2. 可能发生 OOM

    • 如果循环分配的内存未释放,堆的增长会持续消耗物理内存和交换空间,最终触发 OOM。
    • 操作系统会选择终止当前进程,防止系统崩溃。
  3. 优化:避免内存泄漏

    • 使用 delete或智能指针(如 std::unique_ptr)释放内存:

      1
      2
      3
      4
      
      for (int i = 0; ; i++) {
          int* ptr = new int[1000];
          delete[] ptr; // 释放内存
      }
      
    • 这样堆的使用会稳定在一个范围内,而不会持续增长。


5. 预防问题的措施

5.1 设置内存限制

  • 使用 ulimit限制单个进程的内存使用:

    1
    
    ulimit -v 1000000  # 限制虚拟内存为 1 GB
    

5.2 内存监控

  • 使用工具如 tophtop 监控进程的内存使用情况。

5.3 使用智能指针

  • 避免内存泄漏的最佳实践是使用 C++ 智能指针:

    1
    2
    3
    4
    
    for (int i = 0; ; i++) {
        auto ptr = std::make_unique<int[]>(1000);
        // 不需要手动释放,智能指针会自动回收内存
    }
    

6. 总结

  1. Heap Overflow:在 Linux 系统中,由于虚拟内存的动态分配机制,new 操作不会直接导致堆溢出,但可能导致 OOM。
  2. OOM 的原因:
    • 内存泄漏:分配的内存未释放。
    • 物理内存和交换空间耗尽。
  3. 避免问题的建议:
    • 及时释放分配的内存。
    • 使用智能指针管理内存。
    • 监控和限制进程的内存使用。

死锁的概念,进程调度算法怎么解决死锁

1. 死锁的概念

死锁(Deadlock) 是指两个或多个进程在执行过程中因竞争资源而进入一种相互等待的状态,如果没有外力干预,这些进程将永远无法继续执行。

1.1 死锁的四个必要条件

根据 Coffman 条件,死锁的发生需要以下四个条件同时成立:

  1. 互斥(Mutual Exclusion):
    • 某些资源一次只能被一个进程占用(如打印机、文件等)。
  2. 持有并等待(Hold and Wait):
    • 一个进程已经持有至少一个资源,但又在等待其他被占用的资源。
  3. 不可剥夺(No Preemption):
    • 已分配的资源不能被强制剥夺,只能由进程自愿释放。
  4. 循环等待(Circular Wait):
    • 存在一组进程形成循环等待链,其中每个进程等待下一个进程占有的资源。

1.2 死锁的表现

  • 进程无法继续执行。
  • 系统资源被长时间占用,可能导致其他任务无法完成。

2. 进程调度算法解决死锁的方法

为了避免或解决死锁,操作系统采用了一系列调度算法和策略。以下是常用的解决方法:


2.1 死锁预防(Deadlock Prevention)

通过破坏死锁的必要条件之一,防止死锁的发生。

具体方法
  1. 破坏互斥条件
    • 尽量使用共享资源代替独占资源(如读写锁)。
    • 例如:多个线程同时读取文件,而不独占文件资源。
  2. 破坏持有并等待条件
    • 要求进程在进入临界区之前一次性申请所有所需资源。
    • 缺点:可能导致资源利用率低。
  3. 破坏不可剥夺条件
    • 允许操作系统强制剥夺进程已分配的资源。
    • 例如:如果进程长时间等待,操作系统可以强制回收资源并分配给其他进程。
  4. 破坏循环等待条件
    • 为所有资源编号,要求进程按编号顺序申请资源,避免循环等待。
    • 示例:如果进程 A 持有资源 1 并想申请资源 2,进程 B 想申请资源 1,但没有资源 2,这种分配顺序避免了死锁。

2.2 死锁避免(Deadlock Avoidance)

通过动态分配资源,在分配前确保不会进入死锁状态。

具体方法
  1. 银行家算法(Banker’s Algorithm):
    • 由 Dijkstra 提出,通过模拟资源分配,判断是否会导致死锁。
    • 核心思想:
      • 每次资源分配前,检查系统是否会进入“不安全状态”。
      • 如果分配会导致不安全状态,拒绝分配资源。
    • 示例:
      • 系统有 10 个资源,进程 A 需要 6 个,进程 B 需要 4 个。银行家算法会验证每次分配是否会导致某个进程的需求无法满足,从而避免死锁。

2.3 死锁检测和恢复(Deadlock Detection and Recovery)

允许死锁发生,但通过检测机制发现死锁,并采取措施恢复系统。

具体方法
  1. 死锁检测
    • 定期检查系统中的资源分配图,找出是否存在循环等待。
    • 如果发现循环等待,则判断死锁发生。
  2. 死锁恢复
    • 强制中止一个或多个死锁进程(称为牺牲进程)。
    • 回收资源并分配给其他进程。
    • 示例恢复策略:
      • 按照优先级中止低优先级的进程。
      • 中止占用最多资源的进程。
      • 回滚到死锁前的状态(如果系统支持事务)。

2.4 死锁忽略(Deadlock Ignorance)

在某些场景下,操作系统不主动处理死锁,而由用户或管理员干预。

  • “鸵鸟策略”:
    • 操作系统假设死锁很少发生,因此不采取任何预防或检测措施。
    • 适用于简单或实时系统中,死锁风险低的场景。
    • 缺点:一旦死锁发生,系统可能需要手动重启。

3. 死锁处理策略的比较

策略优点缺点适用场景
死锁预防简单直接,可以完全避免死锁资源利用率低,限制灵活性高可靠性要求的系统,如银行交易系统
死锁避免提高资源利用率,减少死锁发生概率需要提前知道进程资源需求,开销大资源有限且需要动态分配的场景,如嵌入式系统
死锁检测和恢复不限制资源分配,提高灵活性恢复代价高,可能中止关键进程通用场景,尤其是资源竞争较多的复杂系统
死锁忽略无额外开销,简单实现死锁发生时可能需要人工干预,系统不可靠小型或实时系统,死锁风险较低的场景

4. 示例:银行家算法的基本思路

  1. 定义:
    • Available:系统当前可用的资源向量。
    • Max:每个进程最大需求矩阵。
    • Allocation:每个进程当前已分配的资源矩阵。
    • Need:每个进程剩余需求矩阵,Need = Max - Allocation
  2. 分配规则:
    • 分配前检查 Need <= Available
    • 模拟分配后,检查是否仍有一个安全序列(即可以满足所有进程需求)。

5. 总结

  • 死锁的本质:由资源竞争和进程相互等待引起。
  • 解决策略:
    • 预防:破坏死锁的必要条件。
    • 避免:动态检测并规避死锁状态。
    • 检测和恢复:检测死锁并中止或回滚进程。
    • 忽略:假设死锁不会频繁发生,适合低风险场景。
  • 最佳实践:
    • 根据场景选择合适的策略。
    • 尽量减少资源竞争,设计合理的资源分配顺序。

讲讲进程管理

进程管理概述

进程管理 是操作系统的核心功能之一,用于创建、调度、执行和终止进程,并管理其运行所需的资源。它确保多个进程可以有效地共享 CPU、内存、I/O 等系统资源,同时避免冲突。


1. 什么是进程?

1.1 定义

  • 进程是一个程序在运行时的实例,是资源分配和调度的基本单位。
  • 每个进程由以下部分组成:
    1. 代码段:可执行的程序代码。
    2. 数据段:程序运行时使用的数据(全局变量、静态变量等)。
    3. :动态分配的内存。
    4. :函数调用信息、局部变量、返回地址等。

1.2 进程的特点

  • 动态性:进程是程序的运行实例,具有生命周期。
  • 独立性:进程之间通常是独立的,拥有各自的资源和地址空间。
  • 并发性:多个进程可以同时运行,彼此独立或协作。
  • 异步性:进程的运行速度和顺序不确定,受调度影响。

2. 进程的生命周期

2.1 进程的五种状态

  1. 创建(New)
    • 进程被创建但尚未运行。
    • 操作系统为其分配 PCB(进程控制块)和其他资源。
  2. 就绪(Ready)
    • 进程具备运行条件,等待被 CPU 调度执行。
    • 就绪队列保存所有就绪状态的进程。
  3. 运行(Running)
    • 进程正在使用 CPU 资源执行代码。
    • 在单 CPU 系统中,同一时刻只有一个进程处于运行状态。
  4. 等待(Waiting/Blocked)
    • 进程在等待某些事件(如 I/O 完成、信号)时进入该状态。
    • 等待队列保存所有等待状态的进程。
  5. 终止(Terminated)
    • 进程完成任务或被强制终止,操作系统回收资源。

2.2 状态切换

以下是常见的状态切换场景:

  • 就绪 → 运行:CPU 调度器分配 CPU 时间片。
  • 运行 → 等待:进程执行 I/O 操作或等待事件。
  • 运行 → 就绪:时间片耗尽,进程被切换。
  • 等待 → 就绪:等待的事件发生,进程重新进入就绪队列。
  • 运行 → 终止:进程完成任务或被杀死。

3. 进程控制块(PCB)

3.1 定义

  • PCB(Process Control Block)是操作系统为每个进程维护的重要数据结构,包含进程的所有信息。

3.2 PCB 包含的信息

  1. 进程标识符
    • PID(Process ID):唯一标识进程的编号。
    • PPID(Parent PID):父进程的标识符。
  2. 进程状态
    • 当前状态(如就绪、运行、等待等)。
  3. CPU 寄存器状态
    • 包括程序计数器(PC)、堆栈指针(SP)等。
  4. 内存信息
    • 代码段、数据段、堆和栈的基地址和大小。
  5. 资源信息
    • 打开的文件描述符、I/O 设备等。
  6. 调度信息
    • 优先级、时间片、调度队列位置等。

4. 进程调度

4.1 调度的分类

  1. 长程调度(Long-term Scheduling)
    • 决定哪些作业(Jobs)进入系统成为进程。
    • 主要用于批处理系统。
  2. 中程调度(Medium-term Scheduling)
    • 在多任务系统中,决定哪些进程被挂起或恢复。
  3. 短程调度(Short-term Scheduling)
    • 决定哪个进程获得 CPU 使用权。
    • 关键算法涉及 CPU 的分配。

4.2 调度算法

  1. 先来先服务(FCFS)
    • 按到达顺序调度进程。
    • 简单但可能导致长时间等待(“等待时间长的进程饥饿问题”)。
  2. 最短作业优先(SJF)
    • 优先调度执行时间最短的进程。
    • 提高效率,但需要预知执行时间。
  3. 时间片轮转(RR)
    • 为每个进程分配固定的时间片,时间片到后切换进程。
    • 适合交互式系统。
  4. 优先级调度
    • 按进程优先级调度,优先级高的进程先运行。
    • 可以配合抢占机制。
  5. 多级队列调度
    • 将进程按优先级分组,不同优先级队列使用不同的调度策略。

5. 进程通信

5.1 通信方式

  1. 管道(Pipe)
    • 单向通信,用于父子进程之间。
    • 例:匿名管道(pipe())。
  2. 命名管道(FIFO)
    • 支持任意进程间通信。
    • 例:mkfifo 创建命名管道。
  3. 共享内存(Shared Memory)
    • 在多个进程间共享一段内存区域。
    • 高效,但需要同步机制(如信号量)。
  4. 消息队列(Message Queue)
    • 通过消息队列在进程间传递消息。
    • 使用系统调用 msgsndmsgrcv
  5. 信号(Signal)
    • 异步通知机制,用于通知进程事件的发生。
    • 例:SIGKILLSIGINT
  6. 套接字(Socket)
    • 用于跨主机的进程通信。

6. 多线程与多进程的关系

6.1 多线程

  • 线程是进程的执行单元,同一进程的线程共享代码段、数据段和打开的文件描述符。
  • 线程调度比进程切换更轻量。

6.2 多进程

  • 每个进程有独立的地址空间,资源隔离更好,但切换开销较大。

6.3 区别总结

特性多线程多进程
内存共享线程间共享地址空间进程间独立地址空间
资源消耗轻量级,创建和切换开销小重量级,创建和切换开销大
隔离性线程之间共享资源,容易发生数据竞争进程之间独立,隔离性更强
适用场景高性能计算、并发任务高安全性要求的独立任务

7. 常见命令与工具

7.1 进程管理命令

  1. 查看所有进程:

    1
    
    ps -aux
    
  2. 实时查看进程状态:

    1
    
    top
    
  3. 查看进程树:

    1
    
    pstree
    
  4. 杀死进程:

    1
    
    kill -9 <PID>
    

7.2 调试工具

  1. strace

    :跟踪系统调用。

    1
    
    strace -p <PID>
    
  2. gdb

    :调试进程。

    1
    
    gdb <executable> <PID>
    

总结

  • 进程管理是操作系统的核心功能,负责创建、调度和终止进程。
  • 进程的生命周期包括创建、就绪、运行、等待和终止五种状态。
  • 调度算法决定了进程何时运行,常用算法有 FCFS、RR、SJF 等。
  • 进程间通信通过管道、共享内存、消息队列等机制实现。
  • 掌握进程管理有助于理解操作系统的内部运行机制,提高系统调试能力。
本文由作者按照 CC BY 4.0 进行授权