IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

标签:Kernel

共 17 篇相关文章

IT 累计浏览 3,616

Linux内存中的Cache真的能被回收么?

这篇讲的是Linux系统中一个经典但常被误解的问题:那些被buffer和cache占用的内存,到底能不能在需要时被释放。文章从`free`命令的输出切入,指出了三种不同层次的理解,并重点剖析了第二种——即很多人认为buffer/cache内存“随时可释放”的认知其实并不完全准确。 作者清晰解释了page cache和buffer cache的核心区别:前者主要用于缓存文件读写,后者用于块设备I/O缓存。Linux内核确实会在内存压力大时回收这些缓存,但这个过程并非没有代价——回收前必须确保缓存数据与磁盘文件一致,往往会导致瞬间的IO飙升。 文章的真正价值在于通过一个具体的tmpfs实验揭示了回收的边界。当把大量数据存入基于内存的tmpfs文件系统时,这部分内存会体现在`cached`指标里,`free`命令也提示有很多“可用”内存。然而,当尝试手动执行`echo 3 > /proc/sys/vm/drop_caches`进行回收时,这部分内存却无法被释放,因为它本质就是系统分配给tmpfs的物理内存,不属于可回收的缓存范畴。 因此,结论很明确:并非所有在`free`命令中显示为“cached”的内存都能被回收。像tmpfs这类“内存就是存储”的场景,占用的空间是“实实在在”的已使用内存,这与加速文件访问的磁盘缓存有本质区别。理解这一点,对于准确评估系统内存压力至关重要。

IT 累计浏览 3,047

Linux内核文件系统挂载分析

作者从mount系统调用的实现过程入手,聚焦于Linux 3.2.0内核,拆解文件系统挂载的底层机制。文章首先厘清了两个核心数据结构:每个挂载的文件系统都对应一个vfsmount,它维护着文件系统在哈希表、父子关系链表以及名字空间中的位置;path结构则封装了目标挂载点与父文件系统的关联。 核心分析围绕一连串的函数调用展开:系统调用服务例程将参数复制进内核后,便交由do_mount处理。它通过kern_path定位挂载点,随后分发至do_new_mount进行常规挂载。后者的关键步骤是通过do_kern_mount获取源文件系统的vfsmount,并经由do_add_mount执行合法性检查,最终调用graft_tree进行装载。 装载的精髓体现在attach_recursive_mnt中。该函数建立父子映射:让子文件系统的vfsmount指向父vfsmount,并链接到父系统中的挂载点dentry。最后的commit_tree则将这一切“落地”:把新vfsmount置入正确的名字空间链表、全局哈希表以及父文件系统的子文件系统列表中。整个过程清晰地揭示,挂载在内核层面的本质,正是将源文件系统的vfsmount结构以严格的层级关系,嫁接到目标文件系统的目录树之中。

IT 累计浏览 4,846

Linux内核协议栈对于timewait状态的处理

这篇文章从一次生产环境的运维问题切入,详细剖析了Linux内核从2.6.18升级到2.6.32后,系统TIME_WAIT状态连接数显著增多的根因。作者的核心工作是对两个版本内核的代码进行diff,精准定位到了`net/ipv4/inet_timewait_sock.c`文件中的一处关键变更。 问题的核心在于`inet_twdr_hangman`函数里,一行负责轮转回收槽位的代码`twdr->slot = ...`的位置被移动了。在旧版本中,无论当前槽位(slot)的timewait块是否被完全清理,该自增操作都会执行;而在新版本中,它被放入了一个条件分支,仅当当前槽位被成功清空时才执行。这个看似微小的时序调整,改变了内核回收timewait块的调度逻辑,最终导致了回收变慢和积压。 文章不仅给出了结论,更通过分析`inet_timewait_death_row`数据结构与`inet_twdr_hangman`的定时回收机制,完整还原了问题发生的底层路径。对于需要理解TCP连接生命周期管理,或是面临类似内核升级后网络连接数异常的工程师来说,这篇深入源码实现的排障手记提供了非常具体的思路和技术细节。

IT 累计浏览 10,487

linux内核研究笔记(一)内存管理 – page介绍

这篇讲的是 Linux 内核内存管理中最基础的数据结构——`struct page`。作者以一名服务器程序员的视角,从对“虚拟内存”的好奇出发,深入内核底层,剖析了物理内存管理的核心。 文章首先展示了 `page` 结构体的关键字段,并指出它是内核描述物理内存页的最小单元。核心在于,这片物理页在不同场景下被赋予不同角色:作为页缓存(`mapping` 域)加速文件IO,作为私有数据(`private` 域)用于缓冲或交换,或作为页表映射支撑用户空间的 `malloc`。 作者进一步通过宏定义,解释了页帧号(pfn)与 `page` 指针、物理地址、内核逻辑地址之间的转换机制。比如 `pfn_to_page` 本质上是操作全局数组 `mem_map`,巧妙地将连续的物理内存抽象为可索引的对象。文章还厘清了“内核逻辑地址”与“内核虚拟地址”的区别,并点明在 x86_32 架构下 `PAGE_OFFSET` 的由来。 理解 `page` 结构是窥探内核如何管理伙伴系统、slab分配器乃至整个虚拟内存系统的钥匙。这篇笔记从最底层的数据结构切入,为后续理解更复杂的内存管理机制打下了坚实基础。

IT 累计浏览 4,245

Linux下访问文件的基本模式

这篇讲的是Linux内核中几种常见的文件访问方式,作者从底层机制出发,对比了普通模式、同步模式、直接I/O、异步模式以及内存映射这五种模式的运作原理与核心差异。 普通模式依赖页高速缓存,读阻塞、写缓存即返回,是默认的平衡选择。同步模式则通过置位O_SYNC标志,强制写操作直到数据落盘才返回,代价是更高的延迟,但确保了数据持久性。直接I/O(O_DIRECT)完全绕过页高速缓存,在用户空间与磁盘间直接传输,适合数据库等需要自主管理缓存的场景。异步模式通过aio系列系统调用实现非阻塞I/O,进程提交请求后可立即返回处理其他任务,提升了并发处理能力。内存映射则通过mmap将文件映射到进程地址空间,把文件操作转化为内存操作,简化了编程模型并可能提升大文件访问效率。 文章清晰地拆解了每种模式下内核标志位的状态与数据流路径,帮助开发者理解不同I/O策略的适用场景——比如高性能存储系统可能倾向于直接I/O或异步模式,而追求开发简便性的应用则更适合内存映射。通过对比这些模式的适用场景和实现机制,文章为开发者提供了选择I/O策略的清晰指引。

IT 累计浏览 6,403

malloc()之后,内核发生了什么?

作者从一个常见的用户空间操作出发,即进程调用 `malloc()` 后尝试访问内存,一路追踪到内核空间的真实发生过程。文章的核心在于揭示,用户感知到的“内存分配”在内核层面主要通过 `brk` 系统调用来实现,其背后是一套从修改堆描述符到最终响应缺页异常的精密机制。 讲解路径非常清晰:首先,`malloc()` 会触发 `brk` 系统调用,通过 `SYSCALL_DEFINE1(brk,...)` 服务例程来调整进程的堆边界。文中展示了该例程如何检查资源限制、对齐地址,并根据是扩大还是缩小堆,分别调用 `do_brk()` 或 `do_munmap()`。 文章的巧妙之处在于指出,此时内核通常并未立即分配物理内存。`do_brk()` 的核心工作是在进程的虚拟地址空间中分配或合并一个线性区间(VMA),为后续可能的操作“预留地盘”。真正的魔法发生在第二步:当进程首次访问这块新地址时,CPU 会因页表项无效而触发缺页异常。文章接着深入异常处理流程,从 `page_fault` 入口,到 `do_page_fault()` 判断异常类型,最终由 `handle_mm_fault()` 接手。 在 `handle_mm_fault()` 中,内核才开始真正“分配”物理内存——它确保页目录结构完整,然后调用 `handle_pte_fault()` 完成页框的分配与映射。整个过程生动地体现了 Linux 内存管理中“延迟分配”的核心思想:先给予虚拟承诺,待实际使用时再兑现物理资源,从而优化了内存使用效率。这对于理解内存分配的全链路至关重要。

IT 累计浏览 6,404

C的那些事儿

这篇讲的是C语言在Linux生态中的实践心得与工具推荐。作者从C语言作为许多人的编程启蒙谈起,指出尽管学习路径在演变,但C语言在Linux系统编程领域——如操作系统、数据库等高性能场景——仍占据着核心地位。 文章重点分享了提升C语言“品味”的具体路径。一方面推荐使用Source Insight这类静态分析工具,通过代码跳转、关系图等功能,在庞大的开源代码库中理清脉络;另一方面更推崇借助gprof和cgprof进行动态性能分析,生成可视化的函数调用图,直观展示函数调用次数与时间占比,以真实运行数据替代主观猜测。 作者还特别赞赏了Linux的管道(Pipe)机制,它让不同程序能够无缝衔接,实现了二进制层面的高效代码复用,这比单纯的语句级复用更为精妙。文中以通过管道串联grep、awk等命令为例,展现了这种设计的优雅与强大。 整篇文章并非泛泛而谈,而是结合了作者手边的函数手册、亲测有效的工具链(从编译选项`-pg`到生成调用图的完整流程),以及对Linux设计哲学的具体感受,为想在开源世界中精进C语言的读者,提供了一条清晰、可操作的实践思路。

IT 累计浏览 11,682

gdb的基本工作原理是什么?

这篇从一次技术面试的追问出发,解答了GDB调试器背后的核心原理:它如何“控制”被调试程序,以及与操作系统内核的协作关系。 作者没有停留在命令使用层面,而是深入到实现机制。文章指出,GDB工作的关键在于内核提供的ptrace系统调用——它允许一个进程(GDB)去观察和修改另一个进程(被调试程序)的内存、寄存器和执行流。通过ptrace,GDB能设置断点(修改指令为特殊的陷阱指令)、读取寄存器值、在进程停止时检查内存状态,从而实现单步执行和变量查看。此外,文章还触及了GDB如何利用内核的信号机制来捕获断点命中和程序异常。 理解这一层原理,有助于开发者在使用GDB时,更清晰地知道每一次“next”或“print”背后,内核与调试器之间发生了怎样的交互,让调试过程从“黑盒操作”变得更为透明。

IT 累计浏览 4,059

锁是怎么实现的?

这篇讲的是锁在计算机底层的基本实现原理,作者从最基本的机制出发,梳理了实现锁的几种核心方式。 文章首先排除了应用层常见的各类复杂锁,聚焦于最底层的实现。它可能从原子操作说起,比如利用CPU的原子指令来保证单个操作的不可分割性,这是构建一切锁的基石。接着,会探讨更复杂的实现:比如自旋锁如何让线程在“忙等”中循环尝试获取锁,适用于极短临界区;而互斥锁或信号量则可能涉及内核态与用户态的切换,通过让线程挂起和唤醒来避免CPU空转,适用于可能耗时较长的场景。作者或许还会简要提及读写锁如何分离读写权限以优化并发性能。 这种从原理根源讲起的方式,帮助读者跳出了对“锁”这个抽象概念的模糊认知,理解了不同锁策略在性能、开销和适用场景上的根本权衡,为选择和设计正确的并发方案打下了基础。

IT 累计浏览 6,970

Linux操作系统内核3.3版本I/O Stack的流图

这张流程图拆解了Linux 3.3内核的I/O栈结构,由thomas-krenn.com在2012年公开。它从应用层的O_Direct调用开始,清晰地展现了数据路径的完整旅程。 整个流程被分解为几个核心模块:首先涉及直接I/O或经过页缓存的路径,随后进入虚拟文件系统(VFS)层进行文件系统与网络通信的抽象。数据随后到达块I/O层,经过特定的I/O调度算法处理,再由SCSI子系统适配,最终抵达磁盘硬件。 这份资料最大的价值在于其系统性和直观性。它将原本隐含在内核代码中的复杂数据流向,转化为一张可触摸的全局地图。对于需要理解系统底层性能瓶颈、存储调优或文件系统实现的工程师而言,这相当于一份清晰的导航图,帮助准确定位数据在软件与硬件边界之间的每一跳。

IT 累计浏览 3,696

浅析Linux Kernel中的那些链表

这篇讲的是Linux内核中链表的实现。作者从内核开发者最熟悉的链表结构切入,指出它与数据结构教材中的标准链表有着本质区别。 文章的核心在于剖析内核链表的巧妙设计。它并非传统意义上“节点包含数据”,而是采用侵入式设计:链表节点(`list_head`)被嵌入到你想要管理的数据结构本身中。这样,一套通用的链表操作代码就能管理任意类型的数据,无需为每种数据重写实现。 作者详细对比了侵入式链表与非侵入式链表的差异。传统链表需要为数据分配单独的节点内存,而内核链表将节点与数据合为一体,在内存管理上更为高效和灵活。这种设计使得通过一个数据结构中的链表节点,可以反向定位到包含它的整个结构体,这是理解后续很多内核数据结构(如进程队列)的关键。 文章最后可能总结,这种设计牺牲了一点点直观性,但换来了极大的通用性、性能和内存效率,是内核编程中“空间与时间”、“通用与专用”权衡的经典范例。对于想深入理解内核源码的开发者来说,厘清这个基础结构至关重要。

IT 累计浏览 3,195

Linux TASK_IO_ACCOUNTING功能以及如何使用

这篇讲的是Linux内核如何提供进程级别的IO统计能力,以及如何启用和利用它。作者从我们熟悉但粒度有限的iostat工具说起,指出在Linux 2.6.20版本之前,要获取单个进程或线程发起的IO量是相当困难的,通常只能借助systemtap等专业工具。文章介绍的TASK_IO_ACCOUNTING内核功能,正是为了解决这一痛点而诞生的。 文章核心在于阐述这个内核选项的作用机制:开启后,内核会为每个任务维护详细的IO读写字节计数。作者不仅解释了如何在内核配置或启动参数中启用它,还展示了启用后如何通过/proc/[pid]/io文件查看具体数值,以及如何使用disktop等工具进行聚合和可视化。这对于需要进行精细化IO性能分析和故障定位的开发者与系统管理员来说,提供了从理论到实践的完整路径。

IT 累计浏览 4,101

PHP内核介绍及扩展开发指南―类和对象

这篇讲的是PHP底层如何实现类和对象这一核心特性。作者从Zend引擎的视角切入,拆解了PHP对象在内存中的实际表示方式——比如对象在zval中的存储结构、属性哈希表的组织逻辑,以及类信息从编译到执行的完整生命周期。 文章重点分析了PHP 7+中对象创建和方法调用的底层流程。你能看到Zend虚拟机如何通过opline指令实现属性的动态访问,以及PHP如何通过属性槽(property slot)机制优化对象属性的读写性能。这些实现细节正是PHP对象模型高效运行的基础。 对于希望编写PHP C扩展的开发者来说,理解这些机制至关重要。文章将抽象的语言特性映射到具体的内核数据结构和执行流程,为扩展开发中处理自定义类、管理对象生命周期提供了清晰的实现路径。

IT 累计浏览 3,202

思考mysql内核之初级系列1--- mysql的启动过程

这篇文章记录了两位开发者探索MySQL内核的一次独特尝试。他们没有采用常见的代码调试或资料检索的方式,而是从“思考”出发,试图在对内核不甚了解的前提下,通过逻辑推演与逐步验证来理解MySQL的启动过程。 作者将焦点对准了MySQL服务从启动到就绪这一看似平凡却至关重要的过程。他们梳理了从命令发出到进程就绪的关键步骤与核心逻辑链,将启动过程分解为可理解的阶段。这种“从零开始、边想边试”的路径,不仅揭示了启动流程的实现细节,更呈现了一种通过构建心智模型来学习复杂系统的方法。 对于想初窥MySQL内核门径的读者,尤其是那些面对庞大源码感到无从下手的开发者,这篇分享提供了一种亲切的起点:它展示了如何将一个宏大的目标拆解,并通过思考与验证相结合的方式,逐步接近系统的内部运作原理。

IT 累计浏览 2,989

[Ubuntu] 编译内核出现 request_module binfmt464

这篇讲的是作者在Ubuntu系统上定制Linux 2.6.33内核时的一次实践。他打算从一个新版本内核出发,通过裁剪掉明确不相关的硬件驱动模块,来构建一个更精简、更适合自身笔记本的系统。 过程中,编译环节抛出了“request_module binfmt464”相关的错误。这通常指向内核在编译或启动时试图加载某个模块(这里可能是与二进制格式支持相关的模块),但依赖关系或配置出现了问题。作者通过调整内核配置,确保在精简模块的同时,保留系统运行所必需的核心组件,最终解决了这个编译障碍。 文章分享了内核定制化的一个典型片段:追求精简的初衷与遇到意外依赖之间的平衡。对于想自己编译内核、裁剪不必要模块的读者来说,作者遇到的这个具体报错及其排查思路,提供了一个可参考的实例。

IT 累计浏览 3,970

在 Dell PowerEdge 1950 上安装 Linux 2.6.32-rc8 内核的问题与解决

这篇讲的是作者为了实验 Linux 内核的新特性,尝试在一台较老的 Dell PowerEdge 1950 服务器上安装 2.6.32-rc8 版本内核的过程。由于这款服务器硬件的特殊性,直接安装原版内核遇到了不少兼容性问题。 文章详细记录了排查与解决的全过程,核心问题指向了特定硬件与新版内核之间的适配障碍。在 @Sisyphusliu 师兄的技术支持下,作者最终成功解决了问题,让内核在服务器上顺利运行。这不仅是一次成功的“踩坑”记录,也为有类似老旧服务器内核升级需求的读者提供了一份实用的故障排查参考。

IT 累计浏览 3,105

服务器中swap 的划分

这篇讲的是服务器环境中swap空间的规划与划分,内容源自RHEL的官方文档,针对性很强。作者从Linux内存管理机制出发,重点解释了在服务器场景下,为何不能简单地“关闭swap”或“设得越大越好”。 文章的核心在于对比不同配置策略的利弊:比如,将swap作为内存溢出的“安全网”时,应该预留多少空间才合适?如果追求高性能,又该如何通过调整swappiness参数来减少对swap的依赖?这些讨论都紧扣“服务器”这一前提,区分了与桌面环境的不同考量。 它没有停留在理论层面,而是给出了具体的配置建议和考量维度,帮助管理员根据服务器的内存大小、负载类型(如内存敏感型应用)做出权衡。对于需要部署关键业务的运维人员来说,这是一份清晰、实用的配置参考指南。