
简介这是一份围绕 Windows 任务管理器进程管理的操作系统实验文档适合计算机专业学生、操作系统课程初学者及相关自学者使用。文档按背景知识、实验目的、工具准备、实验内容与步骤组织系统介绍应用程序、进程、性能三个选项卡的功能并引导完成终止进程、查看性能计数器和调整进程优先级等操作可帮助读者理解进程管理与系统动态性能观察方法。资源为单个DOC文档压缩包约251KB下载后可直接打开阅读。文档既包含任务管理器各选项页的原理说明也配有可填写实验记录的表格与操作步骤适合用作课程实验参考、实验报告撰写素材或考前复习资料。目前已有1013人学习适合需要快速掌握Windows进程管理入门操作的学习者。1. 任务管理器与进程管理这份实验文档到底能带你练会什么说实话绝大多数人在 Windows 上按 Ctrl Alt Del 打开任务管理器只会做两件事看 CPU 占用或者把卡死的程序“结束任务”。但任务管理器真正值钱的部分——进程分类、优先级调整、进程计数器的读取——反而很少有人系统练过。这份“实验一操作系统Windows‘任务管理器’的进程管理”实验文档恰好把这部分补上了。它用一台 Windows 2000/XP 时代的机器做载体带你完成进程观察、终止、优先级修改三组操作再用 Visual C 6.0 写两个小工程从 API 层面复现进程从创建到消亡的全过程。适合正在上操作系统课、需要交实验报告的学生也适合想补一补 Windows 进程模型底子的从业者。文档里的表格和填空是现成的实验模板照着做一遍进程管理就不再是黑匣子。2. 任务管理器实操从进程归类到终止与优先级调整任务管理器在 Windows 2000 里叫“Windows 任务管理器”到了 Windows XP 增加了“用户名”列这也是实验文档里多次强调的一个观察点。窗口默认由 4 个选项卡组成应用程序、进程、性能、联网。其中“进程”选项卡是本次实验的主战场它显示的栏目可以通过菜单调整默认能看到映像名称、用户名、CPU、内存使用这几列。实验环境里一共显示了 40 个进程文档要求你先区分出系统进程、服务进程和用户进程三类分别填表记录。2.1 按“用户名”列把 40 个进程分成三类打开任务管理器后单击“进程”选项卡观察“用户名”列。Windows XP 的任务管理器在这一列明确区分了 SYSTEM、NETWORK SERVICE、LOCAL SERVICE 和你当前登录的用户名比如 Administrator。判断进程类别有一个基本准则用户名是 SYSTEM 的通常属于系统进程比如 csrss.exe客户端/服务器运行时子系统、winlogon.exe登录进程、services.exe服务控制管理器用户名是 NETWORK SERVICE 或 LOCAL SERVICE 的是服务进程比如 svchost.exe 的多个实例用户名是 Administrator 这类具体用户的则大多是用户进程比如 WINWORD.EXE、IEXPLORE.EXE、taskmgr.exe 本身。实际操作时有个小技巧单击“用户名”列标题可以让进程按用户名排序这样分类统计会快很多。文档中记录的结果是 25 个系统进程、4 个服务进程、12 个用户进程但你在自己的机器上跑出来的数字大概率不同——这很正常实验目的不是让你复现同样数字而是让你建立起“进程归属”的判断方法。需要说明的是实验文档里要求填的表 3-1、3-2、3-3 记录的是映像名称、用户名、CPU、内存使用四项数据建议你每填一行就核对一下任务管理器里的实时值因为 CPU 列是会跳动的。判断依据很简单服务进程通常由 svchost.exe 承载对应 Windows 服务系统进程集中在 Session 0而带窗口界面、由你启动的程序基本都在用户进程列表里。2.2 终止进程先看清楚再动手否则会连带子进程一起杀终止进程是任务管理器最高频的操作也是最容易翻车的操作。实验文档明确提醒被终止的进程没有机会保存状态和数据如果结束的是系统服务系统某些部分可能无法正常工作。更关键的是结束进程会连它直接或间接创建的所有子进程一起终止。文档给的例子是 Outlook 98——终止它的进程树会同时干掉 MAPI 后台处理程序 mapisp32.exe。这个机制今天依然存在比如你结束 Chrome 主进程所有标签页子进程会全部消失未提交的表单内容直接丢失。正确做法分三步。第一步右键单击要终止的进程选择“结束进程”不要选“结束进程树”——除非你确定要把这个进程的所有子进程一并清掉。第二步查看该进程的用户名如果是 SYSTEM 或 LOCAL SERVICE先停下来想想它是不是 Windows 关键服务比如 csrss.exe 或 winlogon.exe 被结束后系统会直接蓝屏或重启。第三步确认没有未保存的数据。实验里要记录终止某进程后的现象比如进程消失、相关子进程也消失把观察到的结果填进实验报告就行。2.3 显示其他进程计数器选择列与排序的隐藏功能进程选项卡默认显示的列有限但“查看”菜单里的“选择列”命令能解锁大量计数器。勾选后进程列表会多出页面错误、句柄计数、USER 对象、GDI 对象、I/O 读写字节等列。这些参数直接对应 Windows 进程模型里的指标句柄计数反映进程打开了多少内核对象USER 对象和 GDI 对象数量反映 GUI 资源占用I/O 读写字节数则能看出进程的磁盘活动量。操作上还有两个细节。第一单击任意列标题即可按该列排序再次单击可以反转排序顺序——比如按“内存使用”降序排列就能一眼找出最吃内存的进程。第二多处理器机器上还能给进程指派处理器右键进程并“设置相关性”把进程限制在指定 CPU 上运行。不过文档也提醒这可能导致整体性能下降因为进程只能在一个核上排队。这个功能放到今天更像是排查多核调度问题的调试工具平时不建议乱动。2.4 更改进程优先级任务管理器里的实时调度实验优先级的调整入口在“进程”选项卡的右键菜单“设置优先级”里可选项从低到高依次是低、低于标准、标准、高于标准、高、实时。实验文档让读者先通过“选择列”把“基本优先级”列显示出来这样调整后可以直接看到进程基础优先级的变化。文档里还提供了一个对比实验把某个进程优先级调到“高”或“实时”观察它的响应速度变化同时留意其他进程是否变卡。这里要解释清楚一个机制任务管理器改的是进程的优先级类Priority Class它对应 Windows 的 PRIORITY_CLASS 概念分为 IDLE_PRIORITY_CLASS、BELOW_NORMAL_PRIORITY_CLASS、NORMAL_PRIORITY_CLASS、ABOVE_NORMAL_PRIORITY_CLASS、HIGH_PRIORITY_CLASS、REALTIME_PRIORITY_CLASS。优先级类会影响系统调度器给该进程内部线程分配的基本优先级区间也就是说它调整的是整个进程的调度权重。实验文档里 3-6 程序把自身优先级设为 HIGH_PRIORITY_CLASS 后任务管理器的“基本优先级”列会相应显示“高”——这就是最直观的验证方式。还有一点值得记录设置优先级不会立即杀死进程也不保证让进程“绝对更快”它只是改变时间片分配的权重。如果目标进程是 CPU 密集型的死循环调到“实时”反而可能让系统严重卡顿因为它的时间片优先级高过了桌面进程。实验做完后记得把优先级调回“标准”否则你可能会发现整个系统变迟钝。文档里提到的“记录操作后所体会的结果”——如果你认真做了这个对比你就是能体会到这种微妙变化的。3. CreateProcess() 创建进程清单 3-5 源码解析与编译验证实验文档的第二大部分跳出任务管理器的图形界面切换到 Visual C 6.0用两个源码工程去复现进程的“一生”。文档开篇给出了一个总纲式陈述Windows 创建的每个进程都以调用 CreateProcess() API 开始以调用 ExitProcess() 或 TerminateProcess() 结束。这一章先看第一个工程 proccreate它演示的是进程如何被创建。3.1 CreateProcess() 的十个参数逐个说清CreateProcess() 是 Windows 进程创建的底层入口签名有十个参数。文档用表格逐一列出了参数名称和用途这里直接提炼成一张速查表参数作用清单 3-5 中的传值lpApplicationName可执行文件路径可为全路径或相对路径szFilename当前 EXE 的绝对路径lpCommandLine传给新进程的命令行参数szCmdLineEXE 路径 克隆 IDlpProcessAttributes进程句柄的安全属性是否可被继承NULL使用默认安全描述符lpThreadAttributes主线程句柄的安全属性NULLbInheritHandles是否允许继承调用者句柄FALSE不继承dwCreationFlags创建标志如 CREATE_SUSPENDED、CREATE_NEW_CONSOLECREATE_NEW_CONSOLElpEnvironment新进程的环境变量块NULL 则继承调用者环境NULLlpCurrentDirectory新进程的当前目录NULL 则继承调用者目录NULLlpStartupInfoSTARTUPINFO 结构体描述窗口外观与输入输出配置silpProcessInformationPROCESS_INFORMATION 结构体返回进程与主线程的句柄和 IDpi最后这个参数是输出参数函数成功后会往里填 hProcess、hThread、dwProcessId、dwThreadId 四项。关于句柄有个关键习惯创建成功后要立即用 CloseHandle() 关闭 hProcess 和 hThread。这不是强迫症而是文档里专门强调的——句柄是内核对象引用不关闭的话会一直占着内核句柄表的槽位长时间大量创建进程的程序会因此耗尽系统资源。实验中虽然有回收机制但你写自己的进程管理工具时务必养成这个习惯。3.2 清单 3-5 完整源码按可复现版本整理原文的清单 3-5 在 OCR 转写过程中出现了一些符号变形比如全角引号和括号混入、变量名大小写不一致。下面是按 Visual C 6.0 可编译标准整理的版本逻辑与原文一致// proccreate.cpp #include windows.h #include iostream #include stdio.h // 创建当前可执行文件的克隆进程并传入克隆 ID void StartClone(int nCloneID) { // 提取当前可执行文件的完整路径 TCHAR szFilename[MAX_PATH]; ::GetModuleFileName(NULL, szFilename, MAX_PATH); // 构造命令行EXE 路径 空格 克隆 ID TCHAR szCmdLine[MAX_PATH]; ::sprintf(szCmdLine, \%s\ %d, szFilename, nCloneID); // 初始化 STARTUPINFO必须设置 cb 成员 STARTUPINFO si; ::ZeroMemory(si, sizeof(si)); si.cb sizeof(si); // PROCESS_INFORMATION 用于接收子进程句柄与 ID PROCESS_INFORMATION pi; // 创建子进程同一 EXE同一命令行新控制台 BOOL bCreateOK ::CreateProcess( szFilename, // 应用程序名 szCmdLine, // 命令行 NULL, // 默认进程安全属性 NULL, // 默认线程安全属性 FALSE, // 不继承句柄 CREATE_NEW_CONSOLE, // 给新进程分配独立控制台 NULL, // 继承调用者环境变量 NULL, // 继承调用者当前目录 si, // 启动信息 pi); // 返回的进程信息 // 释放对子进程的引用防止句柄泄漏 if (bCreateOK) { ::CloseHandle(pi.hProcess); ::CloseHandle(pi.hThread); } } int main(int argc, char* argv[]) { // 当前进程的克隆编号默认从 0 开始 int nClone(0); if (argc 1) { // 从命令行第二个参数解析克隆 ID ::sscanf(argv[1], %d, nClone); } // 打印当前进程 ID 与克隆 ID std::cout Process ID: ::GetCurrentProcessId() , Clone ID: nClone std::endl; // 最多创建 25 层克隆防止无限递归 const int c_nCloneMax 25; if (nClone c_nCloneMax) { StartClone(nClone); } // 暂停 500 毫秒让窗口在屏幕上停留足够长时间 ::Sleep(500); return 0; }这段代码的执行逻辑是main() 先读取命令行参数里的克隆编号如果编号小于 25就调用 StartClone() 创建自己的另一个副本并把编号加 1 传给子进程。于是运行一个 3-5.exe系统里会瞬间出现一串进程链每个进程都打印自己的 PID 和克隆编号。由于创建标志用了 CREATE_NEW_CONSOLE每个克隆进程都会弹出一个新的命令行窗口你在任务栏能看到一连串活动标记——这是验证进程创建成功最直观的现象。3.3 编译步骤与 CreateProcess 的三个易错点在 Visual C 6.0 里打开源码文件先单击“Build”菜单里的“Compile”系统提示当前没有活动项目工作空间、询问是否创建默认空间时点“是”。编译通过后再执行“Build”菜单里的“Build 3-5.exe”生成可执行文件。最后按 Ctrl F5 或在工具栏点“Execute Program”运行。这个流程里有三个典型坑。第一VC6 对源码文件后缀敏感工程文件需要保存在纯英文路径下含中文或空格的路径可能触发编译错误。第二iostream 与 std 命名空间的配合容易出问题——如果编译器报告 cout 未定义检查是否漏了#include iostream以及是否写成了using namespace std;。第三CreateProcess 的第一个参数如果不写全路径而只给文件名系统会按标准搜索顺序查找包括应用程序目录、当前目录、系统目录、PATH 环境变量。实验文档里特意让读者回答“CreateProcess 函数有几个核心参数本项目各参数的值是什么”——这个填空题本质是在考察你对进程创建调用边界的理解程度。运行 3-5.exe 时还有个小细节按 Ctrl S 可以暂停程序执行按 Ctrl Pause 可以终止。多跑几次观察不同批次启动的进程 PID 差异你会发现 Windows 并不保证按固定顺序分配 PID前后两次运行同一程序克隆进程的 PID 变化规律也不同。这一现象可以作为实验报告里的补充观察记录。4. GetProcessVersion 与 GetVersionEx进程版本信息的两种取法实验的第二个源码工程 version 演示的是另一类进程管理操作读取当前进程的 PID、获取需要的最低操作系统版本再读取系统实际运行的 Windows 版本号最后根据版本判断结果提升进程优先级。整个程序演示了进程信息查询的 API 组合用法是理解 Windows 进程“自我认知”的好素材。4.1 清单 3-6 完整源码版本查询与优先级提升// version.cpp #include windows.h #include iostream void main() { // 获取当前进程的 PID DWORD dwIdThis ::GetCurrentProcessId(); // 获取当前进程所需的操作系统主版本号 DWORD dwVerReq ::GetProcessVersion(dwIdThis); WORD wMajorReq (WORD)(dwVerReq 16); WORD wMinorReq (WORD)(dwVerReq 0xffff); std::cout Process ID: dwIdThis , requires OS: wMajorReq . wMinorReq std::endl; // 准备 OSVERSIONINFOEX 结构体保存操作系统版本信息 OSVERSIONINFOEX osvix; ::ZeroMemory(osvix, sizeof(osvix)); osvix.dwOSVersionInfoSize sizeof(osvix); // 获取当前操作系统版本 ::GetVersionEx((LPOSVERSIONINFO)osvix); std::cout Running on OS: osvix.dwMajorVersion . osvix.dwMinorVersion std::endl; // 如果是 Windows NT 系列且主版本号 5提升进程优先级 if (osvix.dwPlatformId VER_PLATFORM_WIN32_NT osvix.dwMajorVersion 5) { ::SetPriorityClass( ::GetCurrentProcess(), // 当前进程 HIGH_PRIORITY_CLASS); // 提升为高优先级 std::cout Task Manager should now indicate this process is high priority. std::endl; } }这段代码的逻辑分三段先用 GetCurrentProcessId() 拿到当前进程的 PID再用 GetProcessVersion() 查询该进程要求的最低系统版本接着用 GetVersionEx() 读取操作系统实际版本最后通过比较平台 ID 和版本号决定是否把当前进程的优先级类提升为 HIGH_PRIORITY_CLASS。dwVerReq 16取的是高 16 位主版本号dwVerReq 0xffff取的是低 16 位次版本号。编译运行后输出结果有三行第一行是本进程的 PID 和它要求的操作系统版本第二行是当前操作系统的真实版本第三行提示任务管理器应该把该进程标记为高优先级。实验文档里的运行记录显示某台机器上 PID 是 5310要求的 OS 版本是 5.0当前系统版本是 6.1任务管理器也能看到优先级列变成“高”。4.2 GetProcessVersion 与 GetVersionEx 的差异对照项目GetProcessVersionGetVersionEx查询对象指定进程传 0 表示当前进程所需的最低系统版本当前操作系统版本返回 OSVERSIONINFOEX 结构体返回值DWORD高 16 位主版本低 16 位次版本BOOL成功返回 TRUE调用前提对进程有 PROCESS_QUERY_INFORMATION 权限无典型用途判断某进程能否在当前系统上运行程序根据操作系统版本调整行为实验文档中的角色与 GetVersionEx 配合确认系统版本为 SetPriorityClass 提前做版本判定这里有一个实际工程经验GetVersionEx 在 Windows 8.1 之后被标记为废弃 API即使程序在 Windows 10/11 上运行不附加 manifest 时它也会返回 Windows 8版本号 6.2来保证兼容性。实验是在 Windows 2000/XP 环境下设计的所以没问题。但你在新系统上复现时如果发现打印出的版本号是 6.2不要怀疑代码写错了——这是微软的兼容性策略。新版代码建议用 RtlGetVersion 或直接读取注册表来获取真实版本号。优先级提升部分在 Windows 10/11 上依然有效。运行后打开任务管理器找到 version.exe 对应的进程它的“基本优先级”列会显示“高”。文档里还有个细节操作在任务管理器的“应用程序”选项卡里右键单击“3-6”任务选择“转到进程”系统会自动跳到进程选项卡并定位到对应进程。这个功能在排查“某个窗口到底是哪个进程”时特别好用值得记下来。4.3 用任务管理器反向验证优先级提升结果这是个我比较推荐做的闭合验证先运行 version.exe 前打开任务管理器进程列表找到同名进程记住它的“基本优先级”是“标准”运行后再看优先级已经变成“高”。如果没变多半是你看错了进程——注意任务管理器里可能同时有多个同名进程要认准 PID 与屏幕输出的一致。文档里的实验记录显示重新设置优先级后再次运行 3-6.exePID 信息变为 4488这说明每一次运行都是独立的新进程优先级是程序启动时自己设置的。如果手动右键把进程优先级调成“低于标准”再运行一遍程序自身会再次把它调回“高”——这一点也值得在报告里写明因为它证明了 SetPriorityClass 对进程优先级有最终决定权。实验文档里还提到两个进阶 APISetProcessAffinityMask() 可以把线程映射到指定处理器SetProcessPriorityBoost() 可以关闭前台应用程序的优先级提升。这两者在多核调试和后台服务优化场景里是常用工具但实验正文没有完整的调用示例。如果你想把实验做深可以仿照清单 3-6 的结构用自己的 PID 调用 SetProcessAffinityMask 并观察任务管理器里“处理器相关性”的变化。5. 避坑任务管理器与 VC6 源码实验的五个常见问题这个实验在两代 Windows 环境下跨度很大从任务管理器图形界面到 VC6 的 API 编程每个环节都藏着不少坑。我按实际操作中最高频的问题整理成五条每条都给出现象、原因与解决路径。5.1 Ctrl Alt Del 按了没反应现象按下组合键没有弹出任务管理器窗口或者弹出来是锁屏界面。原因Windows XP 和 Windows 10/11 对 Ctrl Alt Del 的响应策略不同。XP 直接打开任务管理器Win10/11 跳到安全选项界面需要再点“任务管理器”。另外组策略里可以禁用任务管理器也会导致按键无反应。解决试试 Ctrl Shift Esc 直接打开任务管理器这是绕过安全选项的最快路径。如果还是打不开按 Win R 输入 taskmgr.exe 回车。被组策略禁用时需要管理员在注册表 HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System 下检查 DisableTaskMgr 的值是否为 1改为 0 或删除即可。5.2 结束进程后系统变慢或桌面消失现象在进程列表里结束了某个看起来“不相关”的进程结果桌面图标消失了或者系统突然卡顿。原因结束 explorer.exe 会导致桌面、任务栏全部退出结束 svchost.exe 可能带走多个 Windows 服务连带的网络、音频、打印服务都会停掉。任务管理器是可以直接结束系统关键进程的它不像某些安全软件那样有拦截保护。解决实验前先按“用户名”列排序只操作自己启动的进程比如 3-5.exe、3-6.exe、WINWORD.EXE。如果误杀了 explorer.exe按 Ctrl Alt Del 打开任务管理器点“文件”菜单里的“新建任务运行”输入 explorer.exe 回车桌面会重新加载。svchost.exe 被误杀的话重启系统是成本最低的恢复方案。5.3 VC6 编译通不过报错集中在 iostream 与命名空间现象在 Visual C 6.0 里编译清单 3-5 或 3-6控制台报错提示 cout、endl 未定义或者 sscanf、sprintf 不兼容。原因VC6 对 C 标准的支持非常老iostream 头文件里的符号默认不进入全局命名空间。另外原文转写时可能出现半角引号、全角括号混入的符号错误导致编译器无法解析。解决在 main() 之前显式写using namespace std;并且确认代码里的引号是英文半角。stdio.h 的函数如果报不兼容在预处理器定义里加 _CRT_SECURE_NO_WARNINGS或者改用 sprintf_s 这类安全版本。这类问题在纯 XP VC6 环境下出现概率低但在 Win7/10 上编译经典教材代码时非常常见。5.4 GetVersionEx 在 Windows 10/11 上报出的版本号不对现象编译运行 version.exe输出显示的 Running on OS 版本号与系统设置里的版本号不一致比如系统是 Windows 11 23H2程序却报 6.2。原因GetVersionEx 从 Windows 8.1 开始被微软“锁定”除非程序清单里显式声明支持 Windows 10/11否则 API 固定返回 6.2 版兼容值这是为了避免老程序因版本判断错误而拒绝运行。解决在源码工程里添加 application manifest声明兼容 Windows 10/11 版本或者放弃 GetVersionEx改用 RtlGetVersionntdll 中的未文档化接口或读取注册表HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion里的 CurrentMajorVersionNumber 和 CurrentMinorVersionNumber。实验报告里如果能说明这一差异反而是加分项。5.5 任务管理器改优先级后看不到任何效果现象把某个进程的优先级从“标准”改成“高”但该进程的运行速度、响应速度没有明显变化。原因优先级只影响 CPU 时间片的分配权重对 IO 密集型或网络等待为主的进程几乎无感。而且 Windows 默认允许前台进程有优先级提升普通桌面程序本身就处在有利位置。解决想验证优先级的效果跑一个纯 CPU 密集的循环程序再做对比。比如写个 while(1) 循环空转的 console 程序同时开两个实例一个设为“低”一个设为“高”再观察任务管理器“性能”选项卡里的 CPU 占用曲线——高优先级实例通常会抢到更多的 CPU 时间。实验做完记得恢复默认优先级否则一个“实时”优先级的进程能让整个系统失去响应。6. 进阶用批处理和命令行把进程实验课“自动化”做完清单 3-5 和 3-6 之后还有一件值得做的事把这两个程序从 Visual C 环境里解放出来放到命令行下运行。实验文档的提示部分已经埋了这个问题——在 Windows 2000 的“命令提示符”状态下尝试执行该程序看结果与图形界面运行有没有不同。实践下来的结论是命令行下运行效果更清爽也更适合反复实验。先在 Visual C 的工程目录里找到 Debug 文件夹把 3-5.exe 复制到一个独立目录比如 C:\proc-lab。打开命令提示符cmd进入该目录输入cd C:\proc-lab 3-5.exe屏幕上会依次打印一串进程信息Process ID 和 Clone ID 从 0 到 24 逐条出现每个编号对应一个子进程。再输入3-5.exe 10观察输出会发现进程链从 Clone ID 10 开始创建一直到 25 为止。这是 CreateProcess() 递归调用的直接体现。现在打开任务管理器切到“进程”选项卡按映像名称排序你会看到多个 3-5.exe 同时存在各自 PID 不同——这就是实验里“进程的一生”最直观的画面。更进一步可以写一个批处理脚本把整个过程串起来反复创建和清理进程echo off :loop start C:\proc-lab\3-5.exe 0 timeout /t 2 nul taskkill /IM 3-5.exe /F goto loop这段批处理每两秒创建一次进程链再强制结束所有 3-5.exe 实例。用 taskkill /IM 按映像名称结束比在任务管理器里手动逐一点“结束进程”高效得多。注意 /F 是强制终止3-5.exe 里没有保存状态的逻辑所以不会造成数据丢失。命令行方式最大的好处是能和任务管理器实时对照先运行 3-6.exe输出 PID 后回任务管理器找到同 PID 的进程右键“设置优先级”手动改成“低于标准”再重新运行 3-6.exe观察程序是否又把优先级改回“高”。这个闭环测试做完你就能彻底理解进程优先级是进程自己设置的属性外部手动调整只是一次临时覆盖。我自己的习惯是每跑一个实验程序都先把命令行窗口和任务管理器分屏排好左侧是输出右侧是进程列表。Pid 对应关系一目了然省去了来回切换的麻烦。这种做事方式后来也延续到工作中——凡是涉及进程、端口、句柄的实验我都强制走一遍“命令行启动 任务管理器核对 日志记录”的流程从不凭印象判断。希望帮到你也祝你把这几个实验做出自己的观察记录来。本文还有配套的精品资源点击获取