文章目录
Linux 内核(一)
概念
- 内核:操作系统的核心,负责管理系统的硬件和软件资源,提供通用接口和功能,以支持用户进程的执行。
- POSIX:可移植操作系统接口,定义了操作系统应该为应用程序提供的接口标准,以确保程序在不同操作系统上具有可移植性。
- linux内核:linux的核心组件,管理软硬件资源包括 CPU、内存、文件系统、网络接口等,符合POSIX标准。
内核态与用户态
- CPU 指令权限分级
- 区分内核态与用户态。
- 内核态才拥有最高的权限,可以访问所有资源,如 IO 读写,网络操作。
- 用户态只能执行低级别指令,如需执行高级别指令需切换到内核态。
- 内存空间分级
- 区分内核空间于用户空间。
- 内核空间在高位地址,只有处于内核态的CPU才可以访问。
- 用户空间在低位地址,内核态或用户态的CPU都可以访问。
- 何时会陷入内核态
- 系统调用:用户态下主动切换。
- 异常:用户态下发生了异常,如缺页异常。
- 外围设备中断:当外围设备完成用户请求后,会向CPU发出相应的中断信号。
系统调用
- 系统调用是用户程序访问内核的接口,内核为用户程序提供一些服务。
- 每个系统调用都被赋予一个调用号。
- 系统调用时的过程:
- 将系统调用号和请求参数写入寄存器,执行中断指令。
- 中断处理程序,保存用户态CPU上下文。
- 执行内核态逻辑。
- 恢复用户态CPU上下文。
- 返回用户态。
中断
- 中断是硬件产生的一种信号,用于打断CPU的正常运行,使硬件事件可以被CPU及时处理。
- 中断通过唯一的ID来标识,操作系统根据中断ID使用不同的中断处理程序处理。
- 中断处理程序是设备驱动程序的一部分,通过 request_irq()系统调用注册中断处理程序。
- 中断的处理通常需要分成上下两部分工作。
- 上半部分工作是无法被其他中断打断的,中断处理程序指的是上半部分。
- 下半部分则可以被其他中断打断,目的是延迟执行,实现方法:
- 软中断,在硬中断处理完成后,内核会检测是否有未处理的软中断,有则执行。
- tasklet,利用软中断实现,同一时间相同类型的 tasklet 只能执行一个。
- 工作队列,利用内核线程执行。
内核结构
linux 内核构成:
- 进程管理:控制对CPU的访问,管理进程的创建、销毁、调度等。
- 内存管理:管理内存分配、释放、虚拟内存与物理内存之间的转换等。
- 文件系统
- 网络管理:负责处理网络通信,包括网络接口控制、IP协议和TCP/UDP协议等
- 设备管理:负责与硬件设备进行交互,包括输入输出设备、网络接口、存储设备等。
- 系统调用:为用户空间程序提供访问内核功能的接口。
- 中断处理:负责处理硬件中断和异常事件,以及调度处理器执行中断服务程序。
内存管理
虚拟内存
- 虚拟内存:一种抽象机制,允许每个进程看到一个连续且私有的地址空间(虚拟地址空间)。
- 虚拟内存作用:
- 扩大容量:使用硬盘作为内存,提供比物理内存更大的容量。
- 提高性能:将不活跃的分页交换到硬盘,为活跃进程腾出空间。
- 内存安全:进程间互不干扰,防止内存冲突和数据泄漏。
- 简化编程:提供一致的内存模型,开发时可以假定内存是连续的。
物理内存
- 物理内存:硬件RAM(随机读取存储器,读取时间与位置无关)。
- 地址总线:决定CPU最大寻址能力,32位为4g,64位为16E。
- 区域划分:
- ZONE_DMA:0-16MB,由老式基于ISA的设备通过DMA使用,直接映射到内核的地址空间,不通过MMU。
- ZONE_NORMAL:16MB-896MB,直接映射到内核空间。
- ZONE_HIGHMEM:大于896MB,不直接映射,通过永久映射和临时映射进行访问。
用户空间
- 用户空间:用户进程可以访问的内存空间。
- 位于低位虚拟地址:32位系统下4g内存的前3g,从0x00000000到0xBFFFFFFF。
- 用户空间区域划分:
- 代码段:只读,存放程序的代码。
- 数据段:可读写,存放编译时就有具体值的全局变量或静态变量。
- BSS段:可读写,存放未初始化的全局变量或静态变量,会被初始化为0。
- 堆:可读写,进程运行中动态分配的内存,可动态扩张和收缩,从低位地址向高位地址增长。
- 栈:可读写,函数调用时存放局部变量、参数、返回值等,从高位地址向低位地址增长。
- 内存映射区:存放通过mmap创建的内存映射。
内核空间
- 内核空间:只有处于内核态的CPU才可以访问。
- 位于高位地址,32位系统下4g内存的后1g。
- 内核空间区域划分:
- 直接映射区:与物理地址直接映射,虚拟地址与物理地址间仅相差一个偏移量。
- 高端内存空间:采用非直接映射的方式,使内核可以访问到所有物理内存空间。
内存映射
- 内存映射:将文件或其他对象映射到进程的地址空间,使进程可以像访问内存一样访问这些对象。
- 原理:
- 通过系统调用mmap创建映射。
- 对返回指针进行读写时会产生缺页中断,中断响应时才将数据读取到物理内存。
- 特点:使用内存映射,文件会直接从硬盘复制到用户空间,省去了从硬盘到内核空间再到用户空间的复制过程,从而提高效率。
虚拟地址转物理地址
- 分页机制:内核管理内存的方式,将物理内存和进程地址空间分为固定大小的页,通过页表实现虚拟地址到物理地址到映射。
- 虚拟地址构成:虚拟地址被分成页号和偏移量,页号为页表的索引,偏移量表示在页内的位置。
- 页表:虚拟地址到物理地址的映射表。
- 页表项:页表的每一项,包含了物理页框和访问控制信息(如RWX权限)。
- 页框:物理内存的划分,每个页框可以容纳一个分页的数据。
- 多级分页:将页号进一步分割成多级索引,使二级页表可以分散存储。
- MMU:内存管理单元,在CPU内部,负责地址翻译的硬件模块。
- TLB:页表缓存,在CPU内部,速度接近寄存器,减少MMU做地址翻译时频繁查询物理内存的需求。
- 页表基址寄存器:存放页表的起始物理地址,MMU查找页表时使用。
- 缺页异常:当页表中不存在映射时,会产生缺页异常,中断处理程序负责分配物理页框号,更新页表,最后重新执行产生异常的指令。
- CPU访问内存的过程:
- 产生虚拟地址:CPU根据指令生成虚拟地址,由计数器、基址寄存器、变址寄存器和位移量计算出虚拟地址。
- 检查TLB:MMU检查TLB是否存在页号对应的页表项。
- TLB命中:MMU直接从TLB的页表项中获取物理地址并读取物理内存。
- TLB缺失:MMU需要访问内存来查找页表。
- 查找页表:页表基址寄存器定位页表,逐级查找得到页表项,得到页框地址。
- 访问物理内存:页框地址与偏移量结合得到物理地址,访问物理内存。
- 更新TLB:将此次查找的页表项存入TLB。
- 进程切换与分页机制
- 每个进程都有自己的内存空间及相应的页表结构,通常一级页表驻留在内存中,更高层级页表在首次缺页时分配。
- 进程切换时,内核会保存当前进程的TLB,更新页表基址寄存器到新进程的一级页表。
内存数据结构
- vm_area_struct(虚拟内存区域结构)
- 描述进程地址空间中的一个区域。
- 包含区域起始地址、结束地址、访问权限(读写执行)、映射的文件描述符(如果是文件映射)等。
- vm_area_struct形成链表和红黑树构建了进程的内存管理基础设施。
- 红黑树用于通过地址快速查找。
- 链表按地址升序排列,有助于相邻区域的合并与拆分。
物理内存管理
物理页管理面临问题
- 外部碎片:频繁的分配回收导致页框之间出现空闲区域。
- 内部碎片:页框内部出现的空闲区域。
伙伴系统
- 用于管理物理页框的内存分配算法,目的为减少外部碎片。
- 原理:
- 物理内存划分为相同大小的内存块,块大小为2的幂次方。
- 空闲内存块按大小分类形成链表,每个链表中的内存块大小相同。
- 分配时寻找满足大小要求的最小内存块,如果正好大小相等则直接分配。
- 否则会拆分大块,剩下的空闲内存块加入对应的空闲链表。
- 内存释放时,会检查前后页框是否空闲,进而组合成更大长度的块加入链表。
slab分配器
- 内核中管理小尺寸内核对象的内存分配器,目的减少内部碎片。
- 核心思想是小对象的预分配和缓存复用。
- 原理:
- 将内存划分为slab,每个slab包含多个大小相等的对象。
- 一个slab由一个或多个页框组成。
- kmem_cache代表内核中相同类型的对象的缓存。
- 每个kmem_cache包含三种slab链表,完全分配、部分分配、空。
- 分配时,优先从部分分配链表中选择一个slab,从中分配一个对象。
- 分配与释放时会判断slab是否分配满了,进而转移到对应链表。
虚拟内存分配
用户空间内存分配
- 虚拟内存分配时并没有映射到物理内存,只有实际访问时才发生缺页异常,然后再分配物理内存。
- malloc:调用c标准库分配内存函数时,小于128KB使用brk分配内存,大于128KB使用mmap匿名映射分配内存。
- brk系统调用:改变进程数据段的顶部指针来分配内存。
- mmap系统调用:将文件或其他对象映射到进程地址空间,或者匿名映射。
内核空间内存分配
- kmalloc系统调用:分配的虚拟地址位于内核的直接映射区,基于slab分配器。
- vmalloc系统调用:分配的虚拟地址位于内核的动态内存映射区,一般用于分配大块内存,分配的虚拟地址连续,但物理地址不一定连续。
内存回收
内存不足处理方式
- 回收缓存:经常访问的磁盘数据会形成页缓存,内存不足时首先被释放。
- 触发swap机制:交换内存到硬盘再释放。
- 触发OOM机制:终止部分进程释放资源。
swap机制
- swap是指把进程占用的内存交换到硬盘,然后释放内存。
- 对于进程空间中的不同区域处理方式:
- 代码段:只读,极端情况下直接释放。
- mmap文件映射:被修改过的脏页在交换前先回写文件。
- 匿名内存页:数据段、堆段、栈段、mmap匿名映射,写入交换分区文件。
- LRU内存淘汰:
- 选择匿名内存页写入交换分区的算法。
- LRU表示最近最少使用。
- 算法原理:活跃与非活跃双向链表、页的最近使用标记、从非活跃队尾开始淘汰。