FreeBSD的一个可扩展的并发malloc(3)实现

18 篇文章 0 订阅
10 篇文章 0 订阅

Jason Evans jasone@FreeBSD.org
April 16, 2006

摘要

FreeBSD项目从版本5开始就致力为为多处理器计算系统持续提供可扩展支持。已经取得了足够足够的进展,C类库的malloc(3)内存分配器是运行在多处理器系统的多线程应用的潜在瓶颈。在本文中,我们提供一个新的内存分配器,建立在现有技术的基础上,为应用提供一个可扩展的并发分配。基准测试表明该分配器,对多线程应用内存分配可以随着处理器数量增加而扩展。同时,单线程分配性能与之前的分配器实现类似。

介绍

    FreeBSD之前的malloc(3)由Kamp(1998)实现,通常被称为phkmalloc,长久以来被认为最有用的选择之一,并且相比已发布的其他实现表现良好(Feng and Berger, 2005; Berger et al., 2000; Bohra and Gabber, 2001)。然而,它是在多处理器系统很稀少时设计的,并且对多线程的支持也是参差不齐。FreeBSD项目致力于在SMP系统上持续努力提供可扩展的性能,并且已经取得了充分的进展,malloc(3)已经成为一些多线程应用的一个可伸缩扩展的瓶颈。本文提供一个新的malloc(3)实现,在这里被非正式的称之为jemalloc。
    表面上看,内存分配与声明显得似乎是一个简单的问题,只不过为了对可用的内存保持跟踪,记录它正在使用中,需要“记账”一个标识位。然而,几十年的研究和许多分配器的实现都没有产生一个明显更好的分配器。事实上,度量分配器性能最佳的已知实践非常简单,度量性能的汇总统计也是如此。Wilson et al等人. (1995)对十年前的技术提供了一个很好地回顾。那时多处理器并不是一个重要的问题,另外,该回顾还提供了现代分配器面对的问题的一个全面的总结。下面简要介绍了特别影响jemalloc的各种各样问题,但是并不企图讨论当设计一个分配器时所需要考虑的所有问题。
    分配器性能通常由应用的执行时间组合与应用内存使用的平均值或峰值来度量。它并不能充分的单独度量由分配器代码消费的时间。由于CPU缓存,RAM,和虚拟内存分页的影响,内存布局对如何快速的使运行中的应用停顿有重要的影响。现在普遍认为,综合的跟踪监控甚至不足以度量分配策略对碎片化的影响(Wilson et al., 1995)。分配器性能的唯一确定度量是通过度量应用实际的执行时间和内存使用获得的。这使得在限定分配器性能特征时形成了挑战。考虑到一个分配器对于某些特定的分配模式可能执行的非常差,但是如果所有基准测试的应用没有表现出任何此类模式,那么这个分配器可能会表现执行的很好,尽管某些工作负载表现不佳。这使得在广泛的多元化的应用中进行测试变得很重要。它还促进了分配器设计的一种处理方法,使退化边缘情况的数量与严重程度最小化。
    碎片可以分为内部碎片和外部碎片。内部碎片是个别分配相关浪费空间的度量,由于未使用头部或尾部空间。外部碎片是基于虚拟内存系统的物理空间的度量,也不是直接由应用使用。这两种碎片对性能有不同特征的影响,依赖于应用的行为。理论上,所有碎片类型将会被最小化,但是分配器不得不进行一些权衡,从而影响每种类型碎片的发生次数。

非翻译部分:外部碎片举例:物理内存划出一块100kb,假定一页1kb,总共100页连续的物理内存。应用第一次请求10kb,页下标0-9区间被标记为已使用,第二次申请5kb,10-14被标记为已使用,此时应用释放了0-9区间的分页。此时内存请求20kb,则只能从15-34分配,如果后续没有低于10kb的请求,那么0-9就一直不能被使用,0-9区间就是外部碎片。

    过去的十年里RAM成本明显降低并且在更加丰富,所以phkmalloc被特别优化到更小的工作页集,jemalloc必须更多的关注缓存局部性,并且扩展一下,CPU缓存线的工作集。分页依然可能导致性能急剧下降(并且jemalloc不能忽视这个问题),但现在更普遍的问题是从RAM中获取数据涉及到与CPU性能相关的巨大延迟。
    一个比其他分配器使用更少内存的分配器,不一定能展示更好的缓存局部性,如果应用的工作集不适合缓存,如果工作集是紧凑的压紧在内存中性能将会改善。适时地对象被分配的紧靠在一起,同样倾向于它们在一起使用,那么如果分配器可以连续的分配对象,那么就有可能改进提升局部性。事实上,总内存使用量是缓存局部性的一个合理代理;jemalloc第一次尝试最小化内存使用量,并且尝试仅当它不与第一个目标冲突时分配连续的资源。
    现代的多处理器系统在每个缓存线的基础上保留了内存视图的一致性。如果两个线程同时运行在不同的处理器上并且修改在同一个缓存线里的不同的对象,那么这些处理器必须仲裁决定缓存线的所有权(图1)。这类错误的缓存线共享可能引起严重的性能下降。一种解决这个问题的方法时填补对齐分配,但是填充对齐直接违背了将对象尽可能紧凑的压紧在一起的目标;它可能造成严重的内部碎片。jemalloc在多分配竞技场(Arena)上代替信任来减小这个问题,并且将它留给应用程序作者来填充分配,为了避免在关键的性能代码里错误的缓存线共享,或者在代码里一个线程分配对象,并将对象传递给多个其他线程。
1

    运行在多处理器系统上的多线程应用的分配器的一个主要目标是减少锁竞争。Larson and Krishnan (1998)在展示与测试策略方面做的很好。 他们尝试在他们的分配器里上锁,那并不是使用一个单独的分配器锁,每一个空闲列表有它自己的锁。这有一些帮助,但是没有足够的扩展性,尽管最小化了锁竞争。他们将此归因于“缓存晃动” – 在操作分配器数据结构期间,处理器之间缓存数据的快速迁移。他们的解决方法通过使用多个分配器竞技场(Arena),并且通过线程的唯一标识散列分配线程到各个竞技场Arena(图2)。这工作的很好,并且已经被其他实现使用(Berger et al., 2000; Bonwick and Adams, 2001)。jemalloc使用多竞技场(Arena)方式,但是分配线程到各个竞技场(Arena)动作使用了一个比散列更可靠的机制。
2

    文章的剩余部分描述了主要的jemalloc算法与数据结构,展示了在多处理器系统上多线程应用的性能与可扩展性度量指标的基准测试,与单线程应用的性能与内存使用量一样,并且讨论了内存碎片的度量指标。

算法与数据结构

FreeBSD支持实时的分配器配置通过配置文件/etc/malloc.conf,MALLOC OPTIONS环境变量,或者malloc选项的全局变量。这些提供了一个低开销,无侵入配置机制,对调试与性能调优都有用。jemalloc使用这个机制支持phkmalloc支持的变量调试参数,以及公开的各种与性能相关的变量参数。
    每个应用被配置在运行时有一个固定的竞技场(Arena)数量。默认的,竞技场(Arena)数量取决于处理器数量:
单处理器:所有分配器使用一个竞技场(Arena)。使用多个竞技场(Arena)是没有意义的,因为分配器内竞争仅可能发生在如果一个线程在分配期间被抢占。
多处理器:使用竞技场数量是处理器数量的4倍。通过分配线程至一个竞技场集,单独的竞技场被并发使用的可能性就会降低。
    第一次线程分配或释放内存,它被分配到一个竞技场。与线程的唯一标识散列法不同,竞技场是以循环的方式被选择的,这样就可以保证所有竞技场都有大致相同数量的线程分配给他们。线程唯一标识的可靠伪随机散列(实际上,唯一标识就是指针)是众所周知的困难,这也是最终促成了这种方法的原因。它依然存在线程与其他线程竞争一个特殊的竞技场的可能,但是平均而言,初始化分配(可以理解为一次性的静态分配)不可能比循环分配更好。动态再均衡可能降低竞争,但是必要的记录代价很高,而且很少会带来足够的好处来保证开支。
    Thread-local存储(TLS)对循环分配竞技场的高效实现非常重要,因为每个线程的竞技场分配需要存储在某个地方。Non-PIC code 与一些架构不支持TLS,所以在这些情况下,分配器使用线程的唯一标识散列。线程特定的数据(TSD)机制由pthreads类库提供,是TLS的一个可行的替代选择,除了FreeBSD的pthreads实现在内部分配内存外,如果分配器使用TSD将导致无限递归。
    所有由sbrk(2) 或 mmap(2) 从内核请求内存都以“块”大小的倍数进行管理,块的base地址始终是块大小的倍数(图 3)。这样块的对齐允许对一个分配关联的块的计算是一个常量时间。块通常由一些特殊的竞技场(Arena)管理,并且观察这些关联对纠正分配器的功能很关键。块大小默认为2 MB。
3

    分配大小的种类有三大类:small, large, and huge。所有分配请求都四舍五入到最接近的大小分类的边界。Huge的分配比一个块的一半还大,并且直接基于专用块。关于huge的分配的元数据被存储在一个单独的红黑树。因为大多数应用创建的huge分配很少,所以使用一个单独的树不会是可扩展性的问题。
    对于small 与 large 的分配,使用二进制伙伴算法将块切分为页运行。运行可以反复的分成两半,小到只有一页,但是仅能以切分过程相反的方式合并。运行的状态信息被存储在每个块的开头作为页映射。通过将这些信息从运行中分离出来存储,页只有他们在使用它时才会被触及。这还允许将运行资源奉献给大型分配,这些分配大于页的一半,但不大于块的一半。
    Small的分配分成3个子类目:tiny,quantum-spaced,与sub-page。现代架构根据数据类型对指针强加对齐约束。malloc(3)需要返回为任何目的而适当对齐的内存。这种最坏情况下的对齐要求在这里被称为量子大小(quantum size)(通常为16字节)。在实践中,2的幂次方对齐适用于tiny的分配,因为他们不能够包含足够大的对象,需要量子对齐(quantum对齐)。图4展示了所有分配大小的size分类。
4

    通过除掉quantum-spaced这类尺寸,为没有子类目的small分配将会很简单。无论怎样,大多数应用主要分配的对象小于512字节,并且quantum spacing的尺寸类大大的降低了平均内部碎片。Large尺寸类可能会引起外部碎片的增加,但是实际上,降低的内部碎片通常大于外部碎片增长的偏移量
    Small分配是分开的,这样每次运行都管理一个单独的尺寸类。区域位图存储在每次运行的开始,这比其他方法有几个优势:

• 位图可以快速扫描到第一个空闲区域,这允许in-use(在用)区域的紧密打包。
• 分配器数据与应用数据是分开的。这降低了应用破坏分配器数据的可能性。这也可能增加了应用数据的局部性,因为分配器数据没有与应用数据混合在一起。
• Tiny区域可以更容易的支持。这将更加困难(如果使用其他方法),例如,如果一个免费列表是嵌在自由区域。
    运行的报文头部有一个潜在的问题:他们使用了应用程序原本可以直接使用的空间。这对于大于运行报文头大小的尺寸类可能造成严重的外部碎片化。为了限制外部碎片,所有都使用multi-page(多页)运行,除了最小的尺寸类外。因此,对于最大的small尺寸类(通常为2kb区域),外部碎片被限制在大概3%。
    由于每次运行限制了它可以管理多少区域,所以必须为每种尺寸类的多次运行做好准备。在任何给定的时间,每个尺寸类最多有一个"当前"运行。当前运行保留到直到它完全充满或完成清空。考虑一下,如果没有滞后机制,一个malloc/free可能导致运行的创建/销毁。为了消除这个问题,运行基于充满度的四分位数分类,并且运行在QINIT的类别永远不会被销毁,它必须首先提升到一个更高的充满度类别(才可被销毁)(图5).
    充满度类别也为从non-full(非满)状态的运行中选择一个新的当前运行提供一个机制。优先级顺序是: Q50, Q25, Q0, 然后 Q75. Q75 是最后的选择,因为像这类运行可能是几乎完全满的状态;通常选择像这种的运行可能导致当前运行快速周转(可类比为:上下文快速切换)。
5

原文

https://people.freebsd.org/~jasone/jemalloc/bsdcan2006/jemalloc.pdf

第一部分 综述 第1章 BSD系统的历史和目标 1.1 UNIX系统的历史 1.1.1 UNIX系统的起源 1.1.2 Research小组的UNIX系统 1.1.3 AT&T UNIX System III和System V 1.1.4 伯克利软件发布(BSD) 1.1.5 UNIX无处不在 1.2 BSD和其他系统 1.3 BSD向开放源代码的转变 1.3.1 Networking Release 2 1.3.2 法律诉讼 1.3.3 4.4BSD 1.3.4 4.4BSD-Lite Release 2 1.4 FreeBSD的开发模式 1.5 参考文献 第2章 FreeBSD设计概述 2.1 FreeBSD的功能和内核 2.2 内核结构 2.3 内核服务 2.4 进程管理 2.4.1 信号 2.4.2 进程组和会话 2.5 内存管理 2.5.1 BSD内存管理设计要点 2.5.2 内核中的内存管理 2.6 I/O系统 2.6.1 描述符与I/O 2.6.2 描述符管理 2.6.3 设备 2.6.4 套接口IPC 2.6.5 分散/聚集I/O 2.6.6 多文件系统支持 2.7 设备 2.8 文件系统 2.9 网络文件系统 2.10 终端 2.11 进程间通信 2.12 网络通信 2.13 网络实现 2.14 系统运行 2.15 复习题 2.16 参考文献 第3章 内核服务 3.1 内核结构 3.1.1 系统进程 3.1.2 系统入口 3.1.3 运行时刻的内核结构 3.1.4 内核的入口 3.1.5 从内核返回 3.2 系统调用 3.2.1 调用结果的处理 3.2.2 从系统调用返回 3.3 陷阱和中断 3.3.1 陷阱 3.3.2 I/O设备中断 3.3.3 软件中断 3.4 时钟中断 3.4.1 统计和进程调度 3.4.2 超时 3.5 内存管理服务 3.6 时间服务 3.6.1 真实时间 3.6.2 外部表示 3.6.3 调整时间 3.6.4 时间间隔 3.7 用户、用户组和其他身份标识 3.7.1 主机标识符 3.7.2 进程组和会话 3.8 资源服务 3.8.1 进程优先级 3.8.2 资源利用 3.8.3 资源限制 3.8.4 文件系统配额 3.9 系统运行服务 3.10 复习题 3.11 参考文献 第二部分 进程 第4章 进程管理 4.1 进程管理概述 4.1.1 多程序机制 4.1.2 调度 4.2 进程状态 4.2.1 进程结构 4.2.2 线程结构 4.3 上下文切换 4.3.1 线程状态 4.3.2 底层上下文切换 4.3.3 主动上下文切换 4.3.4 同步 4.3.5 互斥同步 4.3.6 锁管理器的锁 4.3.7 其他同步 4.4 线程调度 4.4.1 4.4BSD的调度程序 4.4.2 线程调度 4.4.3 线程优先级的计算 4.4.4 线程优先级例程 4.4.5 线程运行队列和上下文切换 4.4.6 ULE调度程序 4.5 创建进程 4.6 终止进程 4.7 信号 4.7.1 信号的历史 4.7.2 发送信号 4.7.3 接收信号 4.8 进程组和会话 4.8.1 会话 4.8.2 作业控制 4.9 监管环境 4.9.1 监管环境的语义 4.9.2 监管环境的实现 4.9.3 监管环境的限制 4.10 进程的调试 4.11 复习题 4.12 参考文献 第5章 存储管理 5.1 术语 5.1.1 进程与内存 5.1.2 调页机制 5.1.3 替换算法 5.1.4 工作集模型 5.1.5 交换机制 5.1.6 虚拟内存的优点 5.1.7 虚拟内存的硬件要求 5.2 FreeBSD虚拟内存系统概述 5.3 内核的存储管理 5.3.1 内核映射和子映射 5.3.2 内核地址空间的分配 5.3.3 内核的存储分配程序 5.3.4 内核的区域存储分配程序 5.4 进程独立拥有的资源 5.4.1 FreeBSD的进程虚拟地址空间 5.4.2 缺页处理 5.4.3 映射到对象 5.4.4 对象 5.4.5 对象到页面 5.5 共享存储 5.5.1 mmap模型 5.5.2 共享映射 5.5.3 私有映射 5.5.4 压缩影子链 5.5.5 私有快照 5.6 创建新进程 5.6.1 保留内核资源 5.6.2 复制用户地址空间 5.6.3 不通过复制创建新进程 5.7 执行一个文件 5.8 进程地址空间的操作 5.8.1 改变进程大小 5.8.2 文件映射 5.8.3 改变保护权限 5.9 终止进程 5.10 调页器接口 5.10.1 vnode调页器 5.10.2 设备调页器 5.10.3 物理内存调页器 5.10.4 交换调页器 5.11 调页机制 5.11.1 硬件高速缓存的设计 5.11.2 页面填色 5.12 页面替换 5.12.1 调页参数 5.12.2 pageout守护进程 5.12.3 交换机制 5.12.4 换入进程 5.13 可移植性 5.13.1 pmap模块的作用 5.13.2 初始化和启动 5.13.3 分配和释放映射 5.13.4 改变映射的访问和固定属性 5.13.5 管理页表的使用信息 5.13.6 初始化物理页面 5.13.7 管理内部数据结构 5.14 复习题 5.15 参考文献 第三部分 I/O系统 第6章 I/O系统概述 6.1 从用户到设备的I/O映射 6.1.1 设备驱动程序 6.1.2 I/O队列 6.1.3 中断处理 6.2 字符设备 6.2.1 原始设备和物理I/O 6.2.2 面向字符的设备 6.2.3 字符设备驱动程序的入口点 6.3 磁盘设备 6.3.1 块设备驱动程序的入口点 6.3.2 磁盘I/O请求的排序 6.3.3 磁盘标签 6.4 描述符的管理和服务 6.4.1 打开文件项 6.4.2 管理描述符 6.4.3 异步I/O 6.4.4 文件描述符的上锁机制 6.4.5 描述符上的多路I/O操作 6.4.6 select调用的实现 6.4.7 数据在内核中的转移 6.5 虚拟文件系统的接口 6.5.1 vnode的内容 6.5.2 对vnode的操作 6.5.3 路径名转换 6.5.4 文件系统的导出服务 6.6 与文件系统无关的服务 6.6.1 名字缓存 6.6.2 缓冲区管理 6.6.3 缓冲区管理的实现 6.7 可叠加的文件系统 6.7.1 简单的文件系统层 6.7.2 联合安装的文件系统 6.7.3 其他文件系统 6.8 复习题 6.9 参考文献 第7章 设备 7.1 设备概述 7.1.1 PC的I/O体系结构 7.1.2 FreeBSD海量存储I/O子系统的结构 7.1.3 设备的命名和访问 7.2 GEOM层 7.2.1 术语和拓扑规则 7.2.2 改变拓扑 7.2.3 运行 7.2.4 拓扑的灵活性 7.3 CAM层 7.3.1 SCSI子系统 7.3.2 I/O请求通过CAM子系统的路径 7.4 ATA层 7.5 配置设备 7.5.1 识别设备 7.5.2 自动配置数据结构 7.5.3 资源管理 7.6 复习题 7.7 参考文献 第8章 本地文件系统 8.1 文件系统的分层管理 8.2 inode的结构 8.2.1 inode格式的变化 8.2.2 扩展属性 8.2.3 文件系统的新功能 8.2.4 文件标志 8.2.5 动态的inode 8.2.6 管理inode 8.3 命名 8.3.1 目录 8.3.2 在目录中查找名字 8.3.3 路径名转换 8.3.4 链接 8.4 配额 8.5 文件上锁 8.6 软更新 8.6.1 文件系统中的更新依赖 8.6.2 依赖关系的数据结构 8.6.3 跟踪位映射表的依赖关系 8.6.4 跟踪inode的依赖关系 8.6.5 跟踪直接块的依赖关系 8.6.6 跟踪间接块的依赖关系 8.6.7 跟踪新间接块的依赖关系 8.6.8 跟踪新目录项的依赖关系 8.6.9 跟踪新目录的依赖关系 8.6.10 跟踪删除目录项时的依赖关系 8.6.11 截短文件 8.6.12 回收文件和目录的inode节点 8.6.13 跟踪目录项重命名时的依赖关系 8.6.14 跟踪删除文件时的依赖关系 8.6.15 fsync对软更新的要求 8.6.16 删除文件时对软更新的要求 8.6.17 fsck对软更新的要求 8.6.18 软更新的性能 8.7 文件系统的快照 8.7.1 创建文件系统快照 8.7.2 维护文件系统快照 8.7.3 大型文件系统的快照 8.7.4 快照性能 8.7.5 后台fsck 8.7.6 用户可见的快照 8.7.7 动态的转储 8.8 本地文件库 8.8.1 文件库概述 8.8.2 用户的文件I/O 8.9 伯克利快速文件系统 8.9.1 伯克利快速文件系统的组成 8.9.2 引导块 8.9.3 优化存储空间利用率 8.9.4 读写文件 8.9.5 布局策略 8.9.6 分配机制 8.9.7 将块组成簇 8.9.8 基于扩展的分配 8.10 复习题 8.11 参考文献 第9章 网络文件系统 9.1 历史和概述 9.2 NFS的结构和操作 9.2.1 NFS协议 9.2.2 FreeBSD的NFS实现 9.2.3 客户机/服务器的交互操作 9.2.4 RPC的传输问题 9.2.5 安全问题 9.3 提高性能的技术 9.3.1 租约 9.3.2 崩溃恢复 9.4 复习题 9.5 参考文献 第10章 终端处理 10.1 终端处理模式 10.2 行规程 10.3 用户接口 10.4 tty结构 10.5 进程组、会话和终端控制 10.6 C-list 10.7 RS-232和调制解调器控制 10.8 终端操作 10.8.1 打开终端 10.8.2 输出到行规程 10.8.3 终端的输出 10.8.4 终端的输入 10.8.5 ioctl例程 10.8.6 调制解调器转换 10.8.7 关闭终端设备 10.9 其他行规程 10.10 复习题 10.11 参考文献 第四部分 进程间通信 第11章 进程间通信 11.1 进程间通信的模型 11.2 实现的结构和概述 11.3 内存管理 11.3.1 mbuf 11.3.2 存储管理算法 11.3.3 mbuf工具例程 11.4 数据结构 11.4.1 通信域 11.4.2 套接口 11.4.3 套接口地址 11.4.4 锁 11.5 建立连接 11.6 传送数据 11.6.1 发送数据 11.6.2 接收数据 11.7 关闭套接口 11.8 本地进程间通信 11.8.1 信号量 11.8.2 消息队列 11.8.3 共享内存 11.9 复习题 11.10 参考文献 第12章 网络通信 12.1 内部结构 12.1.1 数据流 12.1.2 通信协议 12.1.3 网络接口 12.2 套接口到协议的接口 12.2.1 协议的用户请求例程 12.2.2 协议的控制输出例程 12.3 协议到协议的接口 12.3.1 pr_output 12.3.2 pr_input 12.3.3 pr_ctlinput 12.4 协议和网络的接口 12.4.1 发送数据包 12.4.2 接收数据包 12.5 路由选择 12.5.1 内核路由选择表 12.5.2 路由选择查找 12.5.3 路由选择重定向 12.5.4 路由选择表接口 12.5.5 用户级的路由选择策略 12.5.6 用户级路由选择接口:路由选择套接口 12.6 缓冲和拥塞控制 12.6.1 协议缓冲策略 12.6.2 队列限制 12.7 原始套接口 12.7.1 控制块 12.7.2 输入处理 12.7.3 输出处理 12.8 网络子系统的其他主题 12.8.1 带外数据 12.8.2 地址解析协议 12.9 复习题 12.10 参考文献 第13章 网络协议 13.1 IPv4网络协议 13.1.1 IPv4地址 13.1.2 广播地址 13.1.3 组播 13.1.4 端口与关联 13.1.5 协议控制块 13.2 UDP协议 13.2.1 初始化 13.2.2 输出 13.2.3 输入 13.2.4 控制操作 13.3 Internet协议(IP) 13.3.1 输出 13.3.2 输入 13.3.3 转发 13.4 TCP协议 13.4.1 TCP连接状态 13.4.2 序号变量 13.5 TCP算法 13.5.1 定时器 13.5.2 往返时间的估计 13.5.3 建立连接 13.5.4 SYN缓存 13.5.5 关闭连接 13.6 TCP输入处理 13.7 TCP输出处理 13.7.1 发送数据 13.7.2 避免糊涂窗口综合症 13.7.3 避免小数据包 13.7.4 确认延迟和窗口更新 13.7.5 重发状态 13.7.6 慢启动 13.7.7 源拥塞的处理 13.7.8 缓冲与窗口大小分配 13.7.9 使用慢启动避免拥塞 13.7.10 快速重发 13.8 ICMP协议 13.9 IPv6 13.9.1 IPv6地址 13.9.2 IPv6数据包格式 13.9.3 套接口API的调整 13.9.4 自动配置 13.10 安全 13.10.1 IPSec概述 13.10.2 安全协议 13.10.3 密钥管理 13.10.4 IPSec实现 13.10.5 密码子系统 13.11 复习题 13.12 参考文献 第五部分 系统运行 第14章 启动和关机 14.1 概述 14.2 引导 14.3 初始化内核 14.4 初始化内核模块 14.4.1 基本服务 14.4.2 初始化内核线程 14.4.3 初始化设备模块 14.4.4 内核的可加载模块 14.4.5 启动进程间通信 14.4.6 启动内核线程 14.5 用户级初始化 14.5.1 /sbin/init 14.5.2 系统的启动脚本 14.5.3 /usr/libexec/getty 14.5.4 /usr/bin/login 14.6 系统运行 14.6.1 内核的配置 14.6.2 系统关机与自动重启 14.6.3 系统调试 14.6.4 同内核传递信息 14.7 复习题 14.8 参考文献 术语表
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值