第九章 内存管理
来源:互联网 发布:java web服务器开发 编辑:程序博客网 时间:2024/06/18 13:10
内存概述
地址空间
内存单元所对应的实际的地址称为物理地址。通常程序操作访问的内存地址称为逻辑地址,CPU通过总线操作的内存地址称为线性地址。
分页
为了有效管理,物理内存分为固定大小的块,称为帧或页。物理页的大小是由硬件决定的,通常为2的幂,像X86平台为4KB。虚拟地址包含页号
和页内偏移,页号作为页表的索引通过MMU映射到物理内存的基地址,再加上页内偏移就得到完整的物理地址。
分页管理将物理页和虚拟页一一映射,这样可以将连续的虚拟内存映射到非连续的物理页上。此外,固定大小的页面在碎片管理,磁盘交换都有
比较好的优越性。
9.2内核的内存分配
内存结构
Linux的内存结构可以很好支持NUMA(Non-Uniform Memory Access Architecture)架构的服务器。NUMA下分布式的一个内存节点称为Node,我们
通常用的单机系统为UMA(Uniform Memory Architecture),就是一个Node。
每个Node下物理内存分成几个Zone(区域),Zone内再对物理页进行管理。所以Linux用了Node->Zone->Page这样一个三层的结构来描述物理内存。
由于硬件和体系结构的原因,一些在特定地址范围内的物理页在使用时有所限制。在X86体系结构上,ISA设备的DMA只有24位的寻址能力,也就是
只能访问内存的16MB。而整个系统的最大物理内存寻址可以大于1GB,超过内核的虚拟地址空间。
为此,Linux将X86的物理内存分为三个Zone。
ZONE_DMA(0~16MB)————DMA内存的分配区域。
ZONE_NORMAL(16MB~896MB)—————正常映射的内存区域。
ZONE_HIGHMEN(896MB~)——————高端内存区域,其中的页不能永久映射到内核地址空间,只做动态映射。
BUDDY页面管理
BUDDY算法是一种经典的内存管理算法,其作用是减少存储空间中的空洞和碎片,增加利用率。BUDDY把内存中的所有页面按照2的幂次进行
分块管理,分配的时候如果没有找到相应大小的块,就把大的块二分成小块;释放的时候,回收的块跟相邻的空闲伙伴块又能合并成大块。这就是
BUDDY(伙伴块)名称的由来。
SLAB内存管理
前面我们看到,BUDDY内存分配的时候,是以页块为单位进行的,而且是2的幂次个块。但是多数的内核对象远小于页的大小,而这些对象在操作
系统的生命周期中会被频繁地申请和释放,并且有实验数据发现,这些对象初始化的时间超过了分配内存和释放内存的总时间,所以需要一种更加
细粒度的针对内核对象的分配算法。
Linux引进了SLAB层来进行细致的内存管理。SLAB分配器最早在SunOS(也就是现在的Solaris的前身)中提出和实现。SLAB分配器有诸多优点,可以
进行不同大小的内存对象的分配,实现快速的内存分配和释放,运用着色优化CPU高速缓存,产生内存碎片小等。
SLAB用高速缓存(kmem_cache)来描述不同的内存对象,每种内存对象对应一个高速缓存。高速缓存内由SLAB来管理对象的内存分配。每个SLAB
是一个或多个连续的物理页面,它提供可用的内存对象。
SLUB/SLOB内存管理
SLUB是2.6.22内核引入的一种新的内核对象缓冲区分配器,其特点是简化设计理念,同时保留SLAB分配器的基本思想:每个高速缓存有多个slab组成,
每个slab包含固定数目的内存对象。
SLUB分配器简化了kmem_cache、SLAB等相关的管理数据结构,摒弃了SLAB分配器中众多的队列概念。
vmalloc内存分配
大多数情况下,只有硬件设备需要得到物理地址连续的内存,而仅供软件模块使用的内存块只要虚拟地址连续就可以了。内核为了满足某些大块内存申请
需求,提供了一组函数:
void *vmalloc(unsigned long size)
void vfree(void *addr)
函数vmalloc()跟应用层提供的malloc()类似,返回一个连续虚拟地址的内存块,但物理块可能是不连续的。
高端内存映射
前面说到,在X86体系结构中,高于896MB的物理内存范围为高端内存ZONE_HIGHMEN,其物理页不能永久映射到虚拟地址上。
内核提供了两组函数用于高端内存的映射。函数kmap()对高端内存和低端内存都能使用,如果是低端内存直接返回该页的线性映射地址,如果是高端内存
建立一个永久映射并返回其地址。因为地址空间的有限,允许的永久映射是有限的,当内存使用完后需要解除这个映射。
函数kmap()允许睡眠,只能用于中断上下文中。内核另外提供的函数kmap_atomic()是非阻塞的,可以运行于中断上下文中。它预先创建好一组保留的映射,
这样内核可以原子地把一个页面映射到保留的映射中。
进程地址空间
内存描述符
Linux使用内存描述符struct_mm_struct来描述一个进程的地址空间信息。
内存映射
前面我们看到,一个进程运行的时候,其用到文件的代码段、数据段等都是映射到内存地址区域的。这个功能是通过系统调用mmap()来完成的。
SLUB是2.6.22内核引入的一种新的内核
多级页表结构
应用程序的访问对象都是虚拟地址,而我们前面提到CPU通过MMU把虚拟地址转化成物理地址从而访问到真正的物理内存。而虚拟内存和物理内存
的映射关系是存放在页表里的。
内核的设计需要考虑到各种不同的CPU上的实现,还要考虑到在64位CPU上的实现,所以要以一种假想、虚拟的CPU和MMU为基础,设计出一种通用
的模型。为此,提供了一个四层页管理架构,来兼容各种架构的CPU。
缺页错误处理
虚拟内存被分配以后,并没有分配相应的物理页面。内核通过缺页错误处理(PageFault)在对虚拟地址进行一次访问的时候创建页表和分配物理页面。CPU
访问一个虚拟地址时,如果没有查到相应的物理页,就会抛出一个缺页错误的内存异常。
页面缓存
页面缓存,通常也就是文件缓存,使用内存页面缓存文件的逻辑内容,从而提高对磁盘文件的访问速度。
顾名思义,页面缓存是以物理页为单位对磁盘文件进行缓存的。对于Linux以及多数的类UNIX系统,系统一般不会让空闲内存太空闲,而是用作页面缓存,
而在有内存请求时逐步释放缓存。所以一般看Linux的空闲内存总是那么少,其实它们正在为加速访问文件系统做贡献。
页面缓存管理
页面缓存使用结构struct_address_space来描述。通常情况下,页面缓存和一个文件节点inode关联,host域记录了这个页面缓存所属的文件。反之,在文件
节点的描述符struct inode中,有一个域i_mapping记录文件的页面缓存。如果是交换页,host为NULL。
Swap内存交换
交换空间是指在外部存储设备中开辟出来的空间,临时存放从内存中调出的页面。因为用于交换页面,所以也是按页划分管理的。Linux允许使用块设备(比如
磁盘分区)和普通文件两种形式来做交换空间,可以并行管理多个交换空间。
用户可以用mkswap命令创建一个新的交换空间,然后使用swapon/swapoff命令加载或卸载交换空间。
内核中使用数据结构struct swap_info_struct来描述一个交换空间,允许最多有MAX_SWAPFILES个。
kswapd和pdflush
kswapd用于物理内存回收,以确保系统的空闲物理内存的数量在一个适当的范围。内存页分配中,如果zone的内存数量低于pages_high的时候,kswapd
进入休眠状态。
pdflush负责内存的脏页面的回写,太多的脏页面意味着风险,如果发生故障,内容容易丢失,而突发的大量物理内存请求则需要大量会写来清理内存,这会
导致很不理想的响应时间。
- 第九章内存管理
- 第九章 内存管理
- 第九章:Win32内存管理
- 第九章 Libgdx内存管理
- C语言第九章:内存管理
- OC - 第九章 内存管理( 初级 )
- Essential Qt 第九章 内存管理
- Objective-C学习笔记第九章内存管理
- 第九章--成本管理
- 第九章 session管理
- 第九章:文件系统管理
- 《C++高效编程:内存与性能优化》第九章:高效内存管理
- [学习笔记—Objective-C]《Objective-C-基础教程 第2版》第九章 内存管理
- 第九章:管理维护sharding
- 第九章-项目人力资源管理
- 第九章 银行管理系统
- 第九章项目人力资源管理
- 第九章 内存模型和名称空间
- android开发记录
- BeanFactory接口包含基本方法
- 枚举类型(C#)
- python:open/文件操作
- 四种常见的 POST 提交数据方式
- 第九章 内存管理
- 对象赋值为null时 内存分配情况,以及什么时候使用效率高
- Algorithms—133.Balanced Binary Tree
- 全局获取Context的技巧,使用intent来传递对象
- dumpsys使用详解
- tomcat native
- iOS开发中遇到的一些小问题
- 使用python显示图像在windows图片查看器中一直显示加载中就是打不开的解决途径
- linux scp远程拷贝文件及文件夹