尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

操作系统PDF高效阅读指南:从进程调度到内存分页的Linux实战验证

操作系统PDF高效阅读指南:从进程调度到内存分页的Linux实战验证 简介这份PDF文档系统梳理了操作系统的核心概念与典型考点面向计算机专业学生、考研复习者及需要夯实系统基础的开发者帮助读者在较短时间内建立对进程管理、存储管理、文件系统等模块的整体认知。资源包内含1个PDF文件大小约110KB内容以概念定义、对比分析和例题演算为主适合作为课堂笔记的补充或考前速查手册。文档覆盖进程上下文的三类组成、进程与线程及作业之间的对应关系、动态分页管理机制、连续文件与索引文件等物理结构的查找时间与空间开销对比并整理了覆盖与交换的区别、分区与分页及段页式等存储管理方式。此外还给出用P、V操作和信号量设计进程同步的示例以及OPT、LRU算法下缺页次数与缺页率的计算题便于读者边学边练、检验掌握程度。目前已有775人学习下载适合需要集中复习操作系统重点、查漏补缺的读者参考使用。1. 从一份“详细完整版操作系统.pdf”说起为什么目录比正文更值得先读很多人拿到一份几百页的操作系统讲义第一反应是从第一页开始啃结果卡在“中断向量表”就再也没翻过第二章。真正高效的做法是先看目录结构因为操作系统的知识不是线性堆叠的而是围绕四条主线展开进程与线程的调度、内存的分页管理、文件系统的抽象、以及设备与并发的协调。一份“详细完整版”的 PDF 之所以厚往往是因为它把这四条线各自展开成了独立章节又在交叉处补了大量例子。这份材料适合两类人一类是要应付操作系统期末复习、需要把零散概念串成体系的学生另一类是工作几年后发现自己只会调 API、却说不清fork到底复制了什么、mmap为什么比read快的工程师。前者需要的是知识地图后者需要的是把 PDF 里的原理映射回自己每天写的代码。下面按“先立住概念、再落到可复现的操作、最后收在排错技巧”的顺序展开中间会穿插 Linux 上的实际命令和最小代码让纸面上的分页、线程、VFS 都能在终端里看到影子。2. 进程、线程与调度从 PDF 概念到 Linux 可观测命令2.1 进程和线程的区别别只背“资源分配单位”PDF 里通常会给出一句标准答案进程是资源分配的基本单位线程是 CPU 调度的基本单位。这句话没错但它解释不了为什么 Java 里创建一个线程比创建一个进程便宜得多也解释不了java 线程等待都完成这类搜索背后真正的痛点——线程之间的生命周期管理。从内核视角看Linux 并不严格区分进程和线程两者都用task_struct表示区别在于是否共享地址空间、文件描述符表和信号处理。用clone()系统调用时传入不同的标志位就得到不同级别的共享。常见做法是用pthread_create创建线程它最终走的就是带CLONE_VM | CLONE_FS | CLONE_FILES的clone。# 查看一个进程下所有线程-T 显示线程-p 指定 PID ps -T -p 1234 # 输出中 SPID 就是线程 IDTID同一 PID 下多个 SPID 即多线程逻辑说明ps -T把每个线程单独列一行SPID列即内核视角的线程 ID。参数-p限定进程避免刷屏。如果看到某个 SPID 的%CPU长期接近 100而进程整体 CPU 也高说明热点在单个线程里这时候再去看线程池配置才有意义。2.2 线程池参数怎么设corePoolSize 不是拍脑袋搜索热词里进程池、线程池、java线程等待都完成同时出现说明很多人卡在“池子开多大、怎么等全部结束”。以 Java 的ThreadPoolExecutor为例核心参数有四个corePoolSize、maximumPoolSize、keepAliveTime、workQueue。它们的关系是任务先填核心线程核心满了进队列队列满了才扩到最大线程再满就触发拒绝策略。// 一个可复现的最小线程池配合 CountDownLatch 等待全部完成 int n 8; ExecutorService pool new ThreadPoolExecutor( n, // corePoolSize常驻线程数 n * 2, // maximumPoolSize峰值线程数 60L, TimeUnit.SECONDS, // 空闲线程存活时间 new LinkedBlockingQueue(100) // 有界队列防止无限堆积 ); CountDownLatch latch new CountDownLatch(10); for (int i 0; i 10; i) { pool.execute(() - { try { /* 业务逻辑 */ } finally { latch.countDown(); } // 每个任务结束减一 }); } latch.await(); // 主线程阻塞直到计数归零 pool.shutdown();逻辑说明CountDownLatch的计数在构造时给定countDown()减一await()阻塞到零。参数上corePoolSize一般按 CPU 核数或 IO 等待比例来定纯计算任务取Runtime.getRuntime().availableProcessors()IO 密集可以放大到 2 到 4 倍。队列一定要有界否则maximumPoolSize永远不会生效任务会一直堆在队列里直到 OOM。2.3 调度策略在 PDF 里怎么讲在top里怎么看PDF 讲调度一般会列 FCFS、SJF、时间片轮转、多级反馈队列。落到 Linux 上默认是 CFS完全公平调度用红黑树按虚拟运行时间排序。你不需要改调度器但要知道nice值和cgroup权重会影响谁先跑。# 查看进程的调度策略和优先级 chrt -p 1234 # 输出 SCHED_OTHER 即 CFSSCHED_FIFO/SCHED_RR 是实时策略逻辑说明chrt -p打印指定 PID 的调度类和优先级。普通进程是SCHED_OTHER实时进程才有SCHED_FIFO或SCHED_RR。如果 PDF 里讲到“实时调度可能导致低优先级饥饿”这里的输出就是活例子——把某个线程设成SCHED_FIFO且优先级高它不主动让出就会一直占 CPU。3. 分页管理与内存把 PDF 里的页表画到/proc里3.1 分页解决了什么页表项里到底存了什么分页管理的核心动机是让物理内存不必连续分配同时用虚拟地址给每个进程一个独立视图。PDF 里会画多级页表x86-64 常见是四级PGD、PUD、PMD、PTE。每个页表项除了物理页框号还有存在位、读写位、用户/内核位、脏位、访问位。缺页中断就是硬件发现存在位为 0触发内核去分配或换入。搜索热词里64位操作系统显示4gb内存只有2gb可用和分页有关一部分物理内存被内核、显存、ACPI 等占用另一部分可能被硬件保留操作系统能用的不等于插满的容量。这不是分页的 bug而是地址空间映射的结果。3.2 用/proc/[pid]/maps和smaps验证虚拟内存布局# 查看某进程的虚拟内存区域 cat /proc/1234/maps # 只看汇总含 Rss、Pss、Shared 等 cat /proc/1234/smaps_rollup逻辑说明maps每行是一个 VMA虚拟内存区域字段依次是地址范围、权限、偏移、设备、inode、路径。smaps_rollup把各段汇总Rss是实际驻留物理内存Pss是按共享比例分摊后的值。参数上Pss比Rss更适合判断一个进程真实占了多少内存因为共享库会被多个进程分摊。3.3 一个最小缺页实验mmap大文件后按页触碰#include sys/mman.h #include fcntl.h #include unistd.h #include stdio.h int main() { int fd open(big.bin, O_RDONLY); // 映射 1GBPROT_READ 只读MAP_PRIVATE 私有映射 char *p mmap(NULL, 1UL30, PROT_READ, MAP_PRIVATE, fd, 0); if (p MAP_FAILED) { perror(mmap); return 1; } // 每隔 4096 字节触碰一次每次触碰触发一次缺页 for (size_t i 0; i (1UL30); i 4096) { volatile char c p[i]; (void)c; } munmap(p, 1UL30); close(fd); return 0; }逻辑说明mmap只建立映射不分配物理页。循环里每读一页触发一次缺页中断内核才把文件页读入页缓存并建立页表项。参数PROT_READ表示只读MAP_PRIVATE表示写时复制。运行后用smaps_rollup看Rss增长就能把 PDF 里的“按需调页”变成可观测的数字。注意触碰大文件时如果内存紧张内核可能回收已读页Rss不一定线性增长这是正常的页回收行为不是代码写错。4. 文件系统与 VFS从sync、根文件系统到分布式文件系统4.1 VFS 的四层抽象superblock、inode、dentry、filePDF 讲文件系统一定会提 VFS因为它让 ext4、btrfs、xfs 甚至分布式文件系统hdfs的客户端都能用同一套open/read/write接口。四个核心对象superblock描述整个文件系统inode描述一个文件dentry描述目录项和路径缓存file描述一个打开的文件实例。根文件系统就是挂载树的最顶端内核启动时必须先挂上它才能执行/sbin/init。搜索热词里根文件系统、sync、vfs连在一起是因为sync系统调用会遍历所有已挂载文件系统的脏页并回写走的就是 VFS 的writeback路径。4.2 用mount、df、debugfs观察文件系统# 查看挂载点和文件系统类型 mount | column -t # 查看各文件系统空间使用 df -hT # 查看 ext4 的 inode 使用情况 df -i逻辑说明mount输出中type列即文件系统类型df -hT的-T显示类型-h人类可读。df -i看 inode 是否耗尽——有时磁盘还有空间但创建不了新文件就是 inode 用完了。参数上btrfs的df输出可能和实际有偏差因为它是 CoW 文件系统需要用btrfs filesystem usage才准。4.3sync与fsync的区别以及什么时候必须用fsync#include fcntl.h #include unistd.h int fd open(data.txt, O_WRONLY | O_CREAT, 0644); write(fd, buf, len); fsync(fd); // 只保证这个文件的脏页落盘 close(fd); // sync(); // 全局回写影响所有文件系统代价大逻辑说明write只是把数据写到页缓存fsync才强制该文件的数据和元数据落盘。sync是全局的会遍历所有文件系统通常只在关机或维护时用。参数上O_CREAT表示不存在则创建0644是权限。数据库和日志类应用必须在关键点调fsync否则掉电可能丢最后几条记录。4.4 分布式文件系统 HDFS 的块抽象和本地文件系统的差别分布式文件系统hdfs把文件切成固定大小的块默认 128MB每块存多副本NameNode 管元数据DataNode 存数据。它和本地文件系统最大的差别是本地文件系统的inode记录块指针HDFS 的元数据在 NameNode 内存里本地fsync保证单机落盘HDFS 的hflush只保证数据到达 DataNode 管道不保证所有副本都写完。做流式写入时如果要求强持久得用hsync。对比项本地 ext4HDFS元数据位置磁盘 inode 表NameNode 内存块大小4KB 页128MB 默认持久化调用fsynchflush/hsync适用场景单机随机读写大文件顺序读写5. 并发排错与验证死锁、线程安全与资源占用的定位手法5.1 线程死锁的四个条件和一次可复现的排查PDF 讲死锁会给四个必要条件互斥、持有并等待、不可抢占、循环等待。实际排错时Java 可以用jstack直接看死锁检测结果。# 找到 Java 进程 PID 后导出线程栈 jstack 1234 stack.txt # 搜索 Found one Java-level deadlock 段落 grep -A 20 deadlock stack.txt逻辑说明jstack会打印每个线程的栈和持有的锁如果 JVM 检测到死锁会专门输出一段Found one Java-level deadlock列出互相等待的线程和锁对象。参数上-l可以额外打印锁的附加信息。定位到之后常见做法是统一加锁顺序或者用tryLock带超时避免无限等待。5.2hashmap 线程安全吗一个高频误用的验证HashMap不是线程安全的多线程并发put在扩容时可能形成环形链表导致get死循环。验证方法是多线程并发写同一个HashMap再用jstack看是否有线程卡在HashMap.get。// 错误示范多线程共享 HashMap MapInteger,Integer map new HashMap(); // 正确做法用 ConcurrentHashMap MapInteger,Integer safe new ConcurrentHashMap();逻辑说明ConcurrentHashMap用 CAS 加分段锁JDK8 后是桶级锁保证并发安全读操作基本无锁。参数上构造时可以指定初始容量和负载因子避免频繁扩容。如果只是读多写少也可以用Collections.unmodifiableMap包装后只读共享。5.3 进程占用文件导致u盘无法弹出的定位搜索热词里u盘无法弹出请先结束占用进程是典型场景。Linux 上用lsof或fuser找到占用者。# 查看谁在占用挂载点 lsof f -- /media/usb # 或者用 fuser 直接列出 PID fuser -m /media/usb逻辑说明lsof f --按文件系统过滤列出所有打开该挂载点下文件的进程。fuser -m按挂载点找进程输出 PID。参数上-m表示挂载点-v可以显示详细信息。找到后先确认进程是否可安全结束再umount不要直接拔。注意强制umount -l只是延迟卸载已打开的文件仍可能写入失败数据完整性无法保证。6. 把 PDF 读薄用perf和ftrace验证调度与缺页的进阶技巧纸面上的调度和分页讲得再细也不如自己抓一次内核事件。perf和ftrace是验证 PDF 结论最直接的工具。比如想确认“时间片轮转是否真的发生”可以用perf sched记录一段时间内的调度事件。# 记录 5 秒内的调度事件 perf sched record -- sleep 5 # 生成调度延迟报告 perf sched latency逻辑说明perf sched record采集sched_switch等事件perf sched latency汇总每个任务的等待时间和运行时间。参数上-- sleep 5表示采集期间运行sleep 55 秒后自动停止。如果看到某个任务的wait time远大于run time说明它在等 CPU这时候再回头看 PDF 里的多级反馈队列就能理解为什么交互式任务需要更高优先级。缺页方面ftrace可以跟踪mm_page_alloc和mm_page_free。# 挂载 tracefs通常已挂载 mount -t tracefs nodev /sys/kernel/tracing # 开启页分配事件 echo 1 /sys/kernel/tracing/events/kmem/mm_page_alloc/enable # 读一会儿 trace cat /sys/kernel/tracing/trace_pipe逻辑说明trace_pipe是实时流每行包含进程名、PID、事件和页框号。参数上events/kmem/下还有mm_page_free、mm_page_alloc_extfrag等可以组合观察内存碎片。跑之前先echo 0 tracing_on暂停配好再开避免刷太快。最后一个实用技巧把 PDF 里每章的核心结论写成一条可执行的验证命令贴在笔记里。比如“分页按需调页”对应smaps_rollup看Rss“CFS 公平调度”对应perf sched latency看等待时间“VFS 统一接口”对应strace -e traceopenat,read,write看系统调用。这样一份“详细完整版”就不再是几百页要背的文字而是一组能在终端里跑出结果的检查项。本文还有配套的精品资源点击获取
返回列表