Linux内核漫谈
文章平均质量分 86
WythePlus
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
Linux内核学习轨迹第十一部:系统卡顿、负载高的根因分析与优化(第四节)
关键技巧:wchan字段会直接显示进程在内核态阻塞的函数名,比如balance_dirty_pages是脏页回写阻塞、mutex_lock是锁竞争阻塞、blkdev_issue_flush是磁盘IO阻塞,一步定位阻塞根因。系统卡顿、负载过高是生产环境最常见的通用故障,核心痛点是「现象泛化,根因分散」——CPU瓶颈、IO阻塞、内存颠簸、中断风暴、锁竞争都可能导致负载飙升,本小节提供。负载高 + %sy/%soft高,内核态/软中断瓶颈,大概率是中断风暴、系统调用滥用、内存颠簸。原创 2026-10-23 11:27:57 · 264 阅读 · 0 评论 -
Linux内核学习轨迹第十一部: 内存泄漏、OOM的全链路排查(第三节)
kmemleak是内核内置的内存泄漏检测器,原理是跟踪内核的内存分配与释放,扫描内存中是否还有指向已分配内存的指针,若没有,则判定为内存泄漏,无需修改代码,仅需开启内核配置即可使用。和用户态OOM(Out Of Memory)两大类,核心痛点是「问题缓慢发生,难以复现,定位难度大」,本小节提供全链路的排查流程与工具链,适配Linux 6.6 LTS内核。开启后,内核运行时检测到内存泄漏,会立即输出完整的警告日志、分配与释放的调用栈,直接定位根因。系列托管API,资源生命周期与设备绑定,自动释放;原创 2026-10-22 11:45:09 · 354 阅读 · 0 评论 -
Linux内核学习轨迹第十一部:死锁、软锁、硬锁的排查与解决(第二节)
锁故障是Linux内核与驱动第二大高频稳定性问题,分为死锁、软锁(soft lockup)、硬锁(hard lockup)三类,这类故障的核心痛点是「系统完全卡死,无日志输出,难以复现和定位」,本小节提供标准化的排查流程与解决方案。lockdep直接明确了死锁的根因:CPU0先拿lock2再拿lock1,CPU1先拿lock1再拿lock2,形成循环等待,必然导致死锁,同时给出了完整的调用栈,可直接定位到代码位置。单个CPU核心占用100%,系统卡顿,可响应NMI中断,内核会输出警告日志与栈回溯。原创 2026-10-21 09:47:58 · 286 阅读 · 0 评论 -
Linux内核学习轨迹第十一部:内核panic、oops的解析与根因定位(第一节)
kdump是内核原生的崩溃转储机制,内核Panic时会自动启动一个最小的捕获内核,将崩溃内核的完整内存镜像保存到磁盘,重启后可通过crash工具做离线深度分析,适合服务器、工业计算机场景。,覆盖生产环境80%以上的高频故障场景,提供标准化的排查流程、可直接复用的工具命令、根因定位方法与落地方案,彻底解决「故障发生后无思路、无方法、无法复现、无法定位」的核心痛点。pstore是内核原生的持久化存储机制,将崩溃日志保存到预留的物理内存中,重启后可完整读取,无需额外存储设备,是嵌入式平台的首选方案。原创 2026-10-20 18:09:20 · 246 阅读 · 0 评论 -
Android系统全核调度揭秘:SystemUI响应背后的黑科技
CPU 调度升压:临时提升对应核心的调度优先级/频率,依次对 CPU0/1/2/3 四个核心执行 boost,是前台进程的专属调度加速。利用率钳位计算:计算每个核心的实际 CPU 利用率,配合 boost 设定频率的上下限,确保升压幅度匹配实际负载,避免过度调频。计算 CFS(完全公平调度器)就绪队列的总负载,这里统计的是 CPU3 的队列负载,为后面把线程迁移到 CPU3 运行做依据。重新计算调度实体的负载,把新线程的负载计入 CPU0 的调度队列,更新全局负载平衡。,选了负载更低的核心执行。原创 2026-10-15 18:08:51 · 209 阅读 · 0 评论 -
Linux内核学习轨迹第八部:网络层:IPv4/IPv6协议实现、路由子系统(第七节)
源码覆盖net/ipv4/(IPv4核心实现)、net/ipv6/(IPv6核心实现)、net/ipv4/route.c/net/ipv4/fib_trie.c(路由子系统核心)三大核心路径,深度拆解IPv4/IPv6协议的内核实现、数据包收发与转发全流程、路由子系统的核心架构与算法,同时提供生产环境的路由配置、问题排查、调优与避坑指南。IP协议头通过可选字段/扩展头机制,支持安全加密(IPsec)、源路由、分片、流标签等扩展功能,无需修改核心协议结构,即可适配新的网络需求,保证了协议的长期生命力。原创 2026-07-19 16:33:54 · 326 阅读 · 0 评论 -
Linux内核学习轨迹第八部:深入解析UDP协议与UDPLite实现(第六节)
IP分片没有重传机制,只要有一个分片丢失,整个包就会被丢弃,可靠性急剧下降。这是Linux内核为UDP隧道提供的标准化扩展接口,VXLAN、IPsec、GRE等基于UDP的隧道协议,通过注册封装回调函数,实现内核态的隧道报文自动解封装,无需经过用户态转发,性能提升一个数量级,是云计算虚拟化网络的核心底层能力。它剥离了TCP复杂的连接管理、可靠重传、流量控制、拥塞控制机制,仅保留最核心的端口寻址和校验和能力,以极低的协议开销、极低的传输延迟,成为实时音视频、DNS、游戏、物联网、虚拟化隧道等场景的首选协议。原创 2026-07-12 21:36:46 · 409 阅读 · 0 评论 -
Linux内核学习轨迹第八部:TCP协议实现深度拆解(第五节)
源码覆盖net/ipv4/tcp.h(核心数据结构)、net/ipv4/tcp_input.c(接收处理)、net/ipv4/tcp_output.c(发送处理)、net/ipv4/tcp_cong.c(拥塞控制)四大核心路径,深度拆解TCP协议的内核实现原理,同时提供生产环境的问题排查、性能调优、避坑指南。生产环境中90%以上的网络问题,都与TCP协议的内核实现、参数配置、状态管理相关。,保证数据的有序、无丢失、无重复、无差错交付,同时通过流量控制、拥塞控制机制,适配不同的网络环境,平衡吞吐量与延迟。原创 2026-07-11 22:02:05 · 399 阅读 · 0 评论 -
Linux内核学习轨迹第八部:深入解析Linux内核数据包发送全链路(第四节)
源码覆盖net/ipv4/tcp_output.c(TCP发送核心)、net/core/dev.c(发送队列核心)、net/sched/(TC流量控制)、drivers/net/ethernet/(网卡驱动发送逻辑),完整拆解从用户态写入数据,到网卡硬件发送完成的全链路流程,深度解析TSO/GSO、TCP发送队列、流量控制、拥塞控制、驱动发送机制,同时提供生产环境的发送性能调优、丢包排查、避坑指南。如果超时未收到ACK,会触发重传机制,重新发送对应的数据包。原创 2026-07-10 11:43:12 · 351 阅读 · 0 评论 -
Linux内核学习轨迹第八部:核心数据结构sk_buff全字段深度解析(第三节)
它为数据包缓冲区预留了headroom(头部空闲空间)和tailroom(尾部空闲空间),协议栈各层添加协议头(以太网头、IP头、TCP头)时,只需移动指针,无需拷贝整个数据包内容,实现了协议栈各层之间的零拷贝处理,极大降低了CPU开销。,是整个网络栈的“流通货币”。针对网络协议的分层特性,sk_buff专门设计了固定的协议头指针(链路层、网络层、传输层),各层协议可以快速定位自己的协议头,无需遍历数据包内容,同时完美兼容IPv4/IPv6、TCP/UDP、VLAN、隧道等多种协议的嵌套场景。原创 2026-07-06 15:32:39 · 675 阅读 · 0 评论 -
Linux内核学习轨迹第八部:套接字Socket层全解析(第二节)
2.ops:协议操作函数集,是Socket层与下层协议的核心桥梁,结构体struct proto_ops中定义了该Socket支持的所有操作(bind/listen/connect/send/recv等),不同的协议(TCP/UDP/UNIX域套接字)会实现不同的函数集,Socket层通过函数指针调用对应的协议逻辑,实现了协议无关性。,是Socket在内核协议栈中的「实体」,存储了该套接字对应的所有协议相关的状态、配置、缓冲区、统计信息,是TCP/UDP等协议处理数据包的核心载体。原创 2026-07-05 12:11:28 · 404 阅读 · 0 评论 -
Linux内核学习轨迹第八部:Linux网络协议栈的整体架构与分层设计(第一节)
Linux网络协议栈是内核最核心、最复杂的子系统之一,是所有网络通信的底层基石。协议栈在数据包收发的全链路预留了大量钩子点,最典型的就是Netfilter框架,允许内核模块、eBPF程序在数据包处理的关键节点插入自定义逻辑,实现防火墙、NAT、流量监控、数据包修改等功能,无需修改内核源码,极大提升了协议栈的灵活性。是内核与物理网卡的桥梁,负责初始化网卡硬件、处理网卡的收发中断、通过NAPI机制高效收发数据包,把链路层的以太网帧转换为网卡可识别的电信号,同时把网卡收到的电信号转换为内核可处理的数据包。原创 2026-07-04 11:49:34 · 365 阅读 · 0 评论 -
Linux内核学习轨迹第七部:设备映射器Device Mapper与LVM实现(第七节)
LVM的核心工作机制是“PE与LE的映射”,即逻辑扩展块(Logical Extent,LE)与物理扩展块(PE)的一一对应,LV的空间由多个LE组成,每个LE对应VG的PE池中一个PE,实现逻辑地址到物理地址的映射,最终通过Device Mapper的target完成IO请求的转发。LVM的元数据(Metadata)是LVM的“配置数据库”,记录了PV、VG、LV的所有配置信息,是LVM正常工作的核心,若元数据丢失或损坏,会导致LVM设备无法识别、数据丢失,因此元数据的备份与恢复至关重要。原创 2026-06-28 17:24:13 · 340 阅读 · 0 评论 -
Linux内核学习轨迹第七部:块设备驱动框架与开发流程(第六节)
gendisk必须绑定一个初始化完成的request_queue,驱动通过blk_mq_init_queue()API创建队列,这是Linux 6.6内核的标准API,替代了旧的blk_init_queue()。块设备驱动的核心职责,是把blk-mq层下发的struct requestIO请求,转换为物理存储硬件可识别的指令,控制硬件完成数据读写,并在IO完成后通知内核,完成整个IO链路的闭环。,完整实现了blk-mq驱动的核心流程,可直接编译运行,用于学习和理解驱动开发的核心逻辑。原创 2026-06-27 21:31:17 · 345 阅读 · 0 评论 -
Linux内核学习轨迹第七部:IO调度器(第五节)
它给每个进程/线程分配一个独立的IO队列,按照进程的权重分配「IO预算」(默认按时间分配,也可按扇区数分配),进程用完预算后,调度器切换到下一个进程的队列,保证所有进程按权重公平占用IO资源。针对读写的业务特性做了差异化设计:读请求通常是同步阻塞的,对延迟更敏感,因此读的截止时间更短,优先级更高;很多人为了提升吞吐量,盲目调大mq-deadline的截止时间、kyber的令牌数,会导致IO排队延迟急剧升高,99.9%长尾延迟恶化10倍以上,尤其是在线业务场景,必须优先保证延迟,再追求吞吐量。原创 2026-06-27 10:33:17 · 388 阅读 · 0 评论 -
Linux内核学习轨迹第七部:多队列块层blk-mq深度拆解(第四节)
发起IO的CPU核心只会操作自己对应的软件队列,不会和其他CPU核心产生锁冲突,多核场景下的并行能力得到了质的提升。量身设计的,彻底解决了传统单队列的全局自旋锁竞争瓶颈,实现了IO请求的全链路并行处理,把NVMe设备的IOPS和延迟性能提升了一个数量级,是现代Linux IO栈的核心基石。blk-mq的核心设计目标就是彻底解决这三个问题,通过**「Per-CPU软件队列 + 多硬件队列」的全并行架构**,消除全局锁,最大化发挥多核CPU和多队列硬件的性能。原创 2026-06-26 21:13:13 · 418 阅读 · 0 评论 -
Linux内核学习轨迹第七部:BIO结构体全解析与IO请求的生命周期(第三节)
BIO通过bi_io_vec数组,把多个不连续的物理内存页,封装到单个BIO中,一次性下发给磁盘,磁盘会把连续的扇区数据,分别写入/读出这些不连续的内存页,极大减少了IO请求数量,降低了硬件中断开销。BIO的本质是(对块设备的一段连续IO操作的标准化封装),它把上层发起的IO请求,拆解为对磁盘连续扇区的读写操作,同时管理IO对应的内存缓冲区、完成回调、错误处理、统计信息等全生命周期信息。理解BIO的结构、字段语义、完整生命周期,是吃透Linux IO栈全链路的核心,也是IO性能调优、故障排查的基础。原创 2026-06-17 10:16:37 · 390 阅读 · 0 评论 -
TEE 全架构世界划分、切换节点与软件组件清单
两个世界的所有切换、状态变更都必须由 EL3 固件完成,这是 TrustZone 安全隔离的硬件根基。,对应 3 套独立软件系统;OP-TEE 硬件适配层,封装消息协议、SMC 调用、中断处理、RPC 分发逻辑。EL3 运行时主体,实现异常向量表、SMC 通用处理、电源管理、安全状态切换。设备,处理安全世界反向 RPC,代理 TA 加载、文件访问、RPMB 操作。世界切换的唯一硬件枢纽,负责 SMC 分发、上下文保存、安全状态切换。安全世界操作系统主体,提供任务调度、内存管理、中断处理、驱动框架。原创 2026-06-16 14:49:38 · 587 阅读 · 0 评论 -
Linux内核模块签名技术
inux 内核运行在系统的最高特权级别(Ring 0)。为了防止恶意代码(如 Rootkit)通过内核模块(非对称加密算法(如 RSA 或 ECDSA)与散列算法(如 SHA-256)的结合应用。下面为您详细拆解该技术的核心原理、签名流程以及内核运行时的验签过程。系统调用,将模块数据读入内核空间,随后内核展开验签逻辑。普通的数字签名(如 GPG 签名)通常会生成一个独立的。内核验证完签名后,会根据 Linux 内核编译配置文件(,任何签名不对或无签名的模块绝对无法加载。直接编译进内核镜像(vmlinuz)原创 2026-06-16 10:07:51 · 324 阅读 · 0 评论 -
Linux内核学习轨迹第七部: 多队列块层blk-mq深度拆解(第四节)
发起IO的CPU核心只会操作自己对应的软件队列,不会和其他CPU核心产生锁冲突,多核场景下的并行能力得到了质的提升。量身设计的,彻底解决了传统单队列的全局自旋锁竞争瓶颈,实现了IO请求的全链路并行处理,把NVMe设备的IOPS和延迟性能提升了一个数量级,是现代Linux IO栈的核心基石。blk-mq的核心设计目标就是彻底解决这三个问题,通过「Per-CPU软件队列 + 多硬件队列」的全并行架构,消除全局锁,最大化发挥多核CPU和多队列硬件的性能。原创 2026-06-13 19:51:46 · 346 阅读 · 0 评论 -
Linux内核学习轨迹第七部:BIO结构体全解析与IO请求的生命周期(第三节)
BIO(Block IO)结构体是Linux通用块层的,文件系统、页缓存层发起的所有块设备IO请求,都会被封装为标准的BIO结构体,经过通用块层、IO调度器、blk-mq多队列层,最终下发给块设备驱动完成物理读写。理解BIO的结构、字段语义、完整生命周期,是吃透Linux IO栈全链路的核心,也是IO性能调优、故障排查的基础。本章节基于(定义在include/linux/bio.h),完整拆解BIO的设计逻辑、核心字段与IO请求的全链路流转。原创 2026-06-13 11:03:39 · 336 阅读 · 0 评论 -
Linux内核学习轨迹第七部:块设备的抽象与核心数据结构(第二节)
struct gendisk(通用磁盘结构体)是Linux内核对一个块设备的最高级抽象,代表一个独立的磁盘设备(比如/dev/sda、/dev/nvme0n1),无论是物理磁盘、分区、逻辑卷、RAID阵列,在内核中都对应一个gendisk实例。这是块设备的核心,所有发往该设备的IO请求都要经过这个队列,它包含了IO调度器、多队列配置、设备IO参数、队列限制等所有IO处理相关的信息,是后续章节的核心拆解对象。比如NVMe驱动会实现自己的nvme_fops函数集,处理NVMe设备的打开、关闭、IO提交等操作。原创 2026-06-11 14:11:36 · 242 阅读 · 0 评论 -
Linux内核学习轨迹第七部:块设备子系统的整体架构(第一节)
线上服务的IO性能瓶颈、磁盘卡顿、数据丢失、存储故障,绝大多数根源都是对块设备子系统的底层机制、IO请求全生命周期、多队列架构、IO调度器的认知不足。,从架构设计、核心数据结构、源码实现、全链路流程、工程实践五个维度,完整拆解块设备子系统与Linux IO栈,同时提供可落地的性能调优、故障排查方案。,内核会对IO请求做合并、排序、批量处理,最大化发挥存储硬件的性能,这是与字符设备最本质的差异。内核提供IO调度器,对请求做合并、排序、优先级调度,优化硬件性能。串口、键盘、终端、声卡。:块设备的核心特征是。原创 2026-06-11 09:43:45 · 380 阅读 · 0 评论 -
Linux内核学习轨迹第六部:特殊文件系统:proc/sysfs/debugfs/tracefs(第六节)
tracefs文件系统是Linux内核ftrace跟踪框架的用户态接口,默认挂载在/sys/kernel/tracing目录,核心目标是:提供一套完整的内核跟踪、调试、性能分析接口,不需要额外的工具,就可以跟踪内核函数的执行、系统调用、中断、IO路径等。sysfs文件系统是基于kobject内核对象模型的伪文件系统,默认挂载在/sys目录,核心目标是:向用户态暴露内核设备、驱动、总线、子系统的层次化信息,是Linux设备模型的用户态接口,也是udev、systemd、容器设备管理的核心依赖。原创 2026-06-10 19:23:49 · 539 阅读 · 0 评论 -
Linux内核学习轨迹第六部:目录项缓存dcache与inode缓存(第五节)
哈希键由「父dentry的地址 + 文件名的哈希值」组成,相同父目录下的相同文件名,哈希值相同,会落到同一个哈希桶中。每个dentry都有d_parent指向父目录的dentry,d_subdirs链表存储该目录下的所有子dentry,d_child是子dentry在父目录链表中的节点,形成了完整的目录树结构,支持目录的顺序遍历。inode缓存是内核为struct inode创建的内存缓存系统,核心目标是缓存文件的元数据,避免每次访问文件都要从磁盘读取inode,减少磁盘IO,提升元数据操作的性能。原创 2026-06-10 11:01:00 · 369 阅读 · 0 评论 -
Linux内核学习轨迹第六部:文件操作的全链路(第四节)
打开的文件没有调用close(),会导致文件句柄泄漏,fd和file实例无法释放,最终超过进程的fd限制(ulimit -n),导致后续open()失败返回EMFILE。O_APPEND模式下,内核会在write()调用时,原子性地把f_pos设置为文件末尾,保证多进程并发追加写时,数据不会相互覆盖,是日志文件的最佳实践。很多工程师忽略close()的返回值,实际上close()可能会返回错误,比如NFS挂载的文件,close()时会等待脏页回写,如果回写失败会返回EIO错误。原创 2026-06-10 09:48:05 · 518 阅读 · 0 评论 -
Linux内核学习轨迹第六部:文件系统的注册、挂载与卸载全流程(第三节)
最基础的挂载,把一个块设备的文件系统挂载到一个目录上,比如mount /dev/sda1 /data,底层流程就是上面的标准流程,需要块设备,读取磁盘超级块,创建super_block实例。挂载命名空间是Linux Namespace的一种,实现了进程间的挂载树隔离,每个挂载命名空间有独立的挂载树,进程只能看到自己所在命名空间的挂载实例,是容器技术的核心底层基础。:把一个文件/目录挂载到另一个文件/目录上,实现目录/文件的镜像访问,比如mount --bind /a /b,访问/b等价于访问/a。原创 2026-06-09 21:15:05 · 485 阅读 · 0 评论 -
Linux内核学习轨迹第六部:VFS四大核心对象:super_block/inode/dentry/file(第二节)
dentry是内存中的对象,不会持久化到磁盘(磁盘上的目录项存储在目录文件的数据块中),内核会把经常访问的dentry缓存起来,形成目录项缓存(dcache),避免每次路径解析都要从磁盘读取目录项,极大提升路径解析的性能。定义了文件打开后的IO操作接口,进程调用open()打开文件时,内核会把inode的i_fop赋值给file实例的f_op,后续的read()/write()等操作,都会调用file->f_op对应的函数。指向该文件的页缓存地址空间,管理文件的所有缓存页,是VFS和页缓存层的桥梁。原创 2026-06-09 09:45:44 · 570 阅读 · 0 评论 -
Linux内核学习轨迹第六部:VFS的设计思想与整体架构(第一节)
很多工程师对VFS的理解停留在「文件操作的封装」表层,却不理解四大核心对象的生命周期、挂载的底层实现、目录项缓存的工作机制、IO全链路的内核流转,最终在遇到实际问题时手足无措。:无论底层是什么资源,VFS都把它抽象为一个file实例,对应一套file_operations操作函数集,用户态通过统一的POSIX接口操作,VFS层把接口调用转发给对应的操作函数,最终实现对底层资源的访问,这就是「一切皆文件」的底层逻辑。为避免内容过长导致异常,本章节先完成前3个核心模块的完整拆解,后续模块可按需继续补充。原创 2026-06-08 21:40:44 · 723 阅读 · 0 评论 -
Linux内核学习轨迹第五部:内存管理相关的问题排查、调优与故障定位 (第十四小节)
└→ memcg信息(如果使用):cat /sys/fs/cgroup/memory//memory.usage_in_bytes、memory.events。├→ 大页信息:grep Huge /proc/meminfo、ls -l /sys/kernel/mm/hugepages/:系统周期性卡顿,pgscan_direct/pgsteal_direct持续很高,kswapd的CPU使用率很高,业务延迟增加。原创 2026-06-08 21:23:39 · 323 阅读 · 0 评论 -
Linux内核学习轨迹第五部: 大页HugePage与透明大页THP (第十三节)
大页(HugePage)是Linux内核的内存优化机制,使用更大的页大小(比如2MB、1GB)替代默认的4KB页,减少页表项的数量,降低TLB(Translation Lookaside Buffer,翻译后备缓冲器)miss的概率,提升内存访问性能。透明大页(THP,Transparent HugePage)是大页的自动化版本,内核会自动把进程的虚拟内存区域合并为大页,不需要用户态手动配置,使用更方便,但也存在一些性能问题,比如内存碎片、内存抖动、延迟增加。THP的大页大小,单位字节,默认2MB。原创 2026-06-08 20:50:12 · 325 阅读 · 0 评论 -
Linux内核学习轨迹第五部:OOM Killer机制全解析 (第十二小节)
memcg(内存控制组)是Linux内核的资源隔离机制,可以限制进程组的内存占用,当进程组的内存占用超过限制时,会触发memcg OOM,只杀死该进程组中的进程,不会影响其他进程组。不要把所有进程的oom_score_adj都设置为-1000:如果所有进程都禁止被OOM杀死,OOM时系统会panic,导致系统崩溃;测试环境,或者触发OOM的进程是内存泄漏的进程,设置为1,直接杀死触发OOM的进程;生产环境,设置为1,OOM时打印所有进程的内存信息,方便排查OOM的原因;测试环境,设置为0,减少日志输出。原创 2026-06-08 18:24:58 · 397 阅读 · 0 评论 -
Linux内核学习轨迹第五部: Swap交换分区机制实现(第十一小节)
很多工程师对swap的认知停留在“扩展内存”的表层,却不理解swap的底层实现、换入换出的全流程、swap分区与交换文件的区别、swap的性能优化,最终导致系统出现swap抖动、性能下降、OOM误杀等问题。当进程再次访问该页时,CPU会触发缺页异常,内核从页表项中提取swap入口地址,找到对应的swap设备和槽位,把页从swap分区换入到物理内存。生产环境优先使用swap分区,性能略高,安全性好;├→ 如果页已经在swap缓存中,且PG_uptodate=1,直接跳到步骤5,从swap缓存中获取页。原创 2026-06-08 16:01:51 · 629 阅读 · 0 评论 -
Linux内核学习轨迹第五部:内存回收机制与 LRU 链表(第十小节)
查看进程的oom_score_adj,oom_score_adj的范围是-1000~1000,值越大,score越高,越容易被杀死;延迟敏感的服务,调大该值,比如设置为100,让WMARK_LOW和WMARK_HIGH更高,提前触发kswapd异步回收,避免直接回收;延迟敏感的服务,调大该值,比如设置为1GB(1048576),预留更多的空闲内存,避免直接回收;SSD,调小该值,比如设置为0(1页),减少不必要的IO。内存抖动的场景,调大该值,比如设置为8,让kswapd每次回收更多的页,减少回收的次数;原创 2026-06-08 15:49:22 · 594 阅读 · 0 评论 -
Linux内核学习轨迹第五部:页缓存Page Cache与回写机制(第九小节)
页缓存的本质是「用相对高速的内存,缓存相对低速的磁盘数据」,减少磁盘IO的次数,极大提升文件访问的性能。页缓存的核心锚点是struct address_space,每个打开的文件对应一个address_space实例,管理该文件的所有缓存页,定义在include/linux/fs.h中,我们在反向映射章节已经介绍过,这里重点拆解页缓存相关的核心字段。文件的写操作,默认也是缓冲IO,不会直接写入磁盘,而是先写入页缓存,把页标记为脏页(PG_dirty),然后由内核的回写线程,异步把脏页回写到磁盘中。原创 2026-06-07 17:50:19 · 287 阅读 · 0 评论 -
Linux内核学习轨迹第五部:反向映射RMAP机制全解析(第八小节)
fork()创建子进程时,子进程会复制父进程的匿名VMA,同时创建anon_vma_chain,把子进程的VMA链接到父进程的anon_vma中,这样,父进程的匿名页被共享后,通过anon_vma就能找到所有子进程中映射了该页的VMA。两者的核心差异:文件页的后备存储是磁盘文件,所有映射了该文件同一偏移的进程,共享同一个页缓存,反向映射的核心是找到所有映射了该文件偏移的VMA;文件页的反向映射是Linux最早实现的反向映射机制,设计相对简单,基于文件的地址空间和VMA的区间树实现。原创 2026-06-07 12:16:21 · 326 阅读 · 0 评论 -
Linux内核学习轨迹第五部:缺页异常处理全链路深度解析(第七小节)
当进程访问的虚拟地址没有建立页表映射,或者访问权限不匹配时,CPU会触发缺页异常,陷入内核,由内核的缺页异常处理函数完成物理内存分配、页表映射、权限调整等操作,异常处理完成后,CPU重新执行触发异常的指令。当进程访问文件映射的虚拟地址,对应的文件页不在页缓存中时,触发文件映射缺页异常,由do_fault()函数处理,通常是主缺页异常,需要访问磁盘。缺页异常处理时,如果系统没有足够的空闲内存,内核会先触发内存回收,如果回收后还是没有足够的内存,会触发OOM Killer,杀死进程释放内存。原创 2026-06-07 10:00:33 · 327 阅读 · 0 评论 -
Linux内核学习轨迹第五部:进程地址空间与虚拟内存管理(第六小节)
用户栈由内核自动管理,不需要用户态调用系统调用,函数调用时,CPU自动把返回地址、栈基址压入栈,分配栈帧;匿名映射:没有对应的磁盘文件,映射的内存初始化为0,用于大内存分配,glibc的ptmalloc会把大于128KB的内存从匿名映射中分配,释放时直接调用munmap()归还给内核,不会产生内存碎片。VMA的操作函数集,定义了该VMA的缺页异常、页迁移、关闭等操作的处理函数,不同类型的VMA有不同的操作函数集,比如文件映射的缺页处理函数会从磁盘读取数据,匿名映射的缺页处理函数会分配空白页。原创 2026-06-07 08:48:28 · 389 阅读 · 0 评论 -
Linux内核学习轨迹第五部:内核内存分配器:SLUB/SLOB/SLAB全解析(第四小节)
每个CPU的kmem_cache_cpu有一个当前活动的Slab页,freelist指向该Slab页中的空闲对象链表,分配时直接从freelist取第一个对象,释放时直接把对象放回freelist,整个过程不需要加锁,因为是每CPU的私有数据,多核之间没有竞争,性能极高。自定义缓存的名称必须唯一,不能和系统已有的缓存重名。内核驱动开发中,如果需要频繁分配和释放固定大小的对象,应该创建自定义的kmem_cache,而不是用kmalloc,性能更高,内存利用率更好,也更容易调试。原创 2026-06-06 21:49:06 · 326 阅读 · 0 评论 -
Linux内核学习轨迹第五部:内存管理子系统-物理内存管理:伙伴系统(Buddy System)深度拆解(第三小节)
不可移动的页只能从MIGRATE_UNMOVABLE类型的链表中分配,可移动的页从MIGRATE_MOVABLE类型的链表中分配,避免不可移动的页分散在可移动的内存中,导致大的连续块被拆分,无法合并,从根源上减少内存碎片。如果这个order=1的块的伙伴块也是空闲的,继续合并为order=2的块,直到伙伴块不空闲,把最终的块挂到对应order的链表中。为了进一步减少内存碎片,内核把空闲块按迁移类型分类,不同类型的内存分配,从对应的迁移类型链表中分配,避免不可移动的页分散在内存中,导致无法合并大的空闲块。原创 2026-06-06 21:04:20 · 296 阅读 · 0 评论
分享