linux内核tmpfs/shmem浅析

简介:

说起共享内存,一般来说会让人想起下面一些方法:
1、多线程。线程之间的内存都是共享的。更确切的说,属于同一进程的线程使用的是同一个地址空间,而不是在不同地址空间之间进行内存共享;
2、父子进程间的内存共享。父进程以MAP_SHARED|MAP_ANONYMOUS选项mmap一块匿名内存,fork之后,其子孙进程之间就能共享这块内存。这种共享内存由于受到进程父子关系的限制,一般较少使用;
3、mmap文件。多个进程mmap到同一个文件,实际上就是大家在共享文件page cache中的内存。不过文件牵涉到磁盘的读写,用来做共享内存显然十分笨重,所以就有了不跟磁盘扯上关系的内存文件,也就是我们这里要讨论的tmpfs和shmem;

tmpfs是一套虚拟的文件系统,在其中创建的文件都是基于内存的,机器重启即消失。
shmem是一套ipc,通过相应的ipc系统调用shmget能够以指定key创建一块的共享内存。需要使用这块内存的进程可以通过shmat系统调用来获得它。
虽然是两套不同的接口,但是在内核里面的实现却是同一套。shmem内部挂载了一个tmpfs分区(用户不可见),shmget就是在该分区下获取名为"SYSV${key}"的文件。然后shmat就相当于mmap这个文件。
所以我们接下来就把tmpfs和shmem当作同一个东西来讨论了。

tmpfs/shmem是一个介于文件和匿名内存之间的东西。
一方面,它具有文件的属性,能够像操作文件一样去操作它。它有自己inode、有自己的page cache;
另一方面,它也有匿名内存的属性。由于没有像磁盘这样的外部存储介质,内核在内存紧缺时不能简单的将page从它们的page cache中丢弃,而需要swap-out;(参阅《linux页面回收浅析》)

对tmpfs/shmem内存的读写,就是对page cache中相应位置的page所代表的内存进行读写,这一点跟普通的文件映射没有什么不同。
如果进程地址空间的相应位置尚未映射,则会建立到page cache中相应page的映射;
如果page cache中的相应位置还没有分配page,则会分配一个。当然,由于不存在磁盘上的源数据,新分配的page总是空的(特别的,通过read系统调用去读一个尚未分配page的位置时,并不会分配新的page,而是共享ZERO_PAGE);
如果page cache中相应位置的page被回收了,则会先将其恢复;

对于第三个“如果”,tmpfs/shmem和普通文件的page回收及其恢复方式是不同的:
page回收时,跟普通文件的情况一样,内核会通过prio_tree反向映射找到映射这个page的每一个page table,然后将其中对应的pte清空。
不同之处是普通文件的page在确保与磁盘同步(如果page为脏的话需要刷回磁盘)之后就可以丢弃了,而对于tmpfs/shmem的page则需要进行swap-out。
注意,匿名page在被swap-out时,并不是将映射它的pte清空,而是得在pte上填写相应的swap_entry,以便知道page被换出到哪里去,否则再需要这个page的时候就没法swap-in了。
而tmpfs/shmem的page呢?page table中对应的pte被清空,swap_entry会被存放在page cache的radix_tree的对应slot上。

等下一次访问触发page fault时,page需要恢复。
普通文件的page恢复跟page未分配时的情形一样,需要新分配page、然后根据映射的位置重新从磁盘读出相应的数据;
而tmpfs/shmem则是通过映射的位置找到radix_tree上对应的slot,从中得到swap_entry,从而进行swap-in,并将新的page放回page cache;

这里就有个问题了,在page cache的radix_tree的某个slot上,怎么知道里面存放着的是正常的page?还是swap-out后留下的swap_entry?
如果是swap_entry,那么slot上的值将被加上RADIX_TREE_EXCEPTIONAL_ENTRY标记(值为2)。swap_entry的值被左移两位后OR上RADIX_TREE_EXCEPTIONAL_ENTRY,填入slot。
也就是说,如果${slot} & RADIX_TREE_EXCEPTIONAL_ENTRY != 0,则它代表swap_entry,且swap_entry的值是${slot} >> 2;否则它代表page,${slot}就是指向page的指针,当然其值可能是NULL,说明page尚未分配。
那么显然,page的地址值其末两位肯定是0,否则就可能跟RADIX_TREE_EXCEPTIONAL_ENTRY标记冲突了;而swap_entry的值最大只能是30bit或62bit(对应32位或64位机器),否则左移两位就溢出了。

最后以一张图说明一下匿名page、文件映射page、tmpfs/shmem page的回收及恢复过程:


目录
相关文章
|
3天前
|
缓存 算法 Linux
深入理解Linux内核调度器:公平性与性能的平衡####
真知灼见 本文将带你深入了解Linux操作系统的核心组件之一——完全公平调度器(CFS),通过剖析其设计原理、工作机制以及在实际系统中的应用效果,揭示它是如何在众多进程间实现资源分配的公平性与高效性的。不同于传统的摘要概述,本文旨在通过直观且富有洞察力的视角,让读者仿佛亲身体验到CFS在复杂系统环境中游刃有余地进行任务调度的过程。 ####
19 6
|
1天前
|
缓存 资源调度 安全
深入探索Linux操作系统的心脏——内核配置与优化####
本文作为一篇技术性深度解析文章,旨在引领读者踏上一场揭秘Linux内核配置与优化的奇妙之旅。不同于传统的摘要概述,本文将以实战为导向,直接跳入核心内容,探讨如何通过精细调整内核参数来提升系统性能、增强安全性及实现资源高效利用。从基础概念到高级技巧,逐步揭示那些隐藏在命令行背后的强大功能,为系统管理员和高级用户打开一扇通往极致性能与定制化体验的大门。 --- ###
15 9
|
1天前
|
缓存 Linux 开发者
Linux内核中的并发控制机制:深入理解与应用####
【10月更文挑战第21天】 本文旨在为读者提供一个全面的指南,探讨Linux操作系统中用于实现多线程和进程间同步的关键技术——并发控制机制。通过剖析互斥锁、自旋锁、读写锁等核心概念及其在实际场景中的应用,本文将帮助开发者更好地理解和运用这些工具来构建高效且稳定的应用程序。 ####
12 5
|
1天前
|
算法 Unix Linux
深入理解Linux内核调度器:原理与优化
本文探讨了Linux操作系统的心脏——内核调度器(Scheduler)的工作原理,以及如何通过参数调整和代码优化来提高系统性能。不同于常规摘要仅概述内容,本摘要旨在激发读者对Linux内核调度机制深层次运作的兴趣,并简要介绍文章将覆盖的关键话题,如调度算法、实时性增强及节能策略等。
|
2天前
|
存储 监控 安全
Linux内核调优的艺术:从基础到高级###
本文深入探讨了Linux操作系统的心脏——内核的调优方法。文章首先概述了Linux内核的基本结构与工作原理,随后详细阐述了内核调优的重要性及基本原则。通过具体的参数调整示例(如sysctl、/proc/sys目录中的设置),文章展示了如何根据实际应用场景优化系统性能,包括提升CPU利用率、内存管理效率以及I/O性能等关键方面。最后,介绍了一些高级工具和技术,如perf、eBPF和SystemTap,用于更深层次的性能分析和问题定位。本文旨在为系统管理员和高级用户提供实用的内核调优策略,以最大化Linux系统的效率和稳定性。 ###
|
1天前
|
Java Linux Android开发
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。
|
4天前
|
Linux 数据库
Linux内核中的锁机制:保障并发操作的数据一致性####
【10月更文挑战第29天】 在多线程编程中,确保数据一致性和防止竞争条件是至关重要的。本文将深入探讨Linux操作系统中实现的几种关键锁机制,包括自旋锁、互斥锁和读写锁等。通过分析这些锁的设计原理和使用场景,帮助读者理解如何在实际应用中选择合适的锁机制以优化系统性能和稳定性。 ####
17 6
|
4天前
|
机器学习/深度学习 负载均衡 算法
深入探索Linux内核调度机制的优化策略###
本文旨在为读者揭开Linux操作系统中至关重要的一环——CPU调度机制的神秘面纱。通过深入浅出地解析其工作原理,并探讨一系列创新优化策略,本文不仅增强了技术爱好者的理论知识,更为系统管理员和软件开发者提供了实用的性能调优指南,旨在促进系统的高效运行与资源利用最大化。 ###
|
6天前
|
算法 Linux 开发者
深入探究Linux内核中的内存管理机制
本文旨在对Linux操作系统的内存管理机制进行深入分析,探讨其如何通过高效的内存分配和回收策略来优化系统性能。文章将详细介绍Linux内核中内存管理的关键技术点,包括物理内存与虚拟内存的映射、页面置换算法、以及内存碎片的处理方法等。通过对这些技术点的解析,本文旨在为读者提供一个清晰的Linux内存管理框架,帮助理解其在现代计算环境中的重要性和应用。
|
3天前
|
监控 网络协议 算法
Linux内核优化:提升系统性能与稳定性的策略####
本文深入探讨了Linux操作系统内核的优化策略,旨在通过一系列技术手段和最佳实践,显著提升系统的性能、响应速度及稳定性。文章首先概述了Linux内核的核心组件及其在系统中的作用,随后详细阐述了内存管理、进程调度、文件系统优化、网络栈调整及并发控制等关键领域的优化方法。通过实际案例分析,展示了这些优化措施如何有效减少延迟、提高吞吐量,并增强系统的整体健壮性。最终,文章强调了持续监控、定期更新及合理配置对于维持Linux系统长期高效运行的重要性。 ####