Linux内存申请与回收

内存申请

申请连续物理内存

按照Linux物理内存管理的描述,得到连续的物理内存有三种方式,很多时候需要申请的内存比较少,达不到一页,这种情况就没必要申请物理内存再自行映射了,内核提供了slab系统来满足要求。
slab实际上是内核在buddy系统基础上构建的资源池(或者说是cache), 它批量申请内存(多页), 完成映射, 用户需要使用内存的时候直接由它返回, 不需要再经过buddy系统。
创建和销毁cache是有代价的, 除非模块内部需要经常申请、释放内存, 否则使用内核提供的cache更加有效。

vmalloc的使用

如果不要求物理内存连续,可以使用vmalloc。 vmalloc得到的虚拟内存连续,但物理上不一定连续,实际上它只是申请一段一段的物理内存,然后将它们映射到连续的线性空间段上而巳。需要注意的是,vmalloc更新的是主内核页表,而不是进程的页表,所以vmalloc返回后,对进程本身而言,它的页表并没有更新,访问得到的虚拟地址会触发缺页异常。
其中,使用grub、 memblock和buddy得到的是物理内存(地址或者page对象),需要自行映射,slab和vmalloc得到的是虚拟内存。

缓存

计算机存在多种存储,cpu访问它们的速度是不同的。

TLB缓存

内存中存放的数据可以分为两类,一类用来内存映射的页表,另一类是普通数据。正常情况下,CPU访问内存需要经过多级页表,最终找到物理内存,中间需要多次访问,如果把最近访问的页表缓存起来,下次再访问的时候,先查找缓存中是否已经存在虚拟内存对应的页表项,可以省略多次内存访问。
以上过程就是TLB,全称为Transation lookaside Buffer,用于虚拟地址到物理地址的转换,提供一个寻找物理地址的缓存区,能够减少寻找物理地址的时间。既然是一种缓存,就会有一致性(coherence)的问题,TLB也不例外。 所谓一致性, 指的是内存和缓存的一致。
  1. 内存映射是与进程相关的. 进程切换会导致一部分映射产生变化. 需要刷新这部分映射对应的TLB。
  2. 物理内存或者虚拟内存重新映射, 导致页表项产生变化, 可能需要刷新产生变化的内存对应的TLB。
  3. 部分内存访问的权限等属性发生变化, 可能需要刷新TLB

内存缓存

这里的内存缓存(cache)是与TLB对应的,TLB缓存的是页表数据, 而它缓存的是普通数据,简称它为 cache。MTRR的全称是Memory Type Range Register, 可以通过它设置一段物理内存的缓存策略。BIOS一般会为内存配置合理的缓存方式, 开机后可以在/proc/mtrr文件中查看 。PAT (Page Attribute Table)可以对MTRR有效补充, 它的粒度为页 (Page), 而且没有数址限制, 编译内核的时候设置 CONFlG_X86_PAT= y使能 PAT。
内存缓存也有一致性的问题,x86上使用wbinvd (wb_invalid), arm上使用flush_cache类函数(flush_cache_range、flush_cache_all等)。

缺页异常

导致缺页异常的场景和合理的处理方式:
第一种场景是程序逻辑错误,分为以下三类。
  • 第一类是访问不存在的地址,最简单的访问空指针
  • 第二类是访问越界,比如用户的程序访问了内核的地址
  • 第三类是违反权限,比如以只读形式映射内存的情况下写内存
第二种情况是访问的地址未映射物理地址,这是正常的。
第三种情况是TLB过时,页表更新后,TLB未更新,这种情况,绕过TLB访问内存中的页表即可。
第四种情况是COW(cope on write, 写时复制),内存没有写权限,写操作导致缺页异常。

异常的处理

缺页异常的处理函数是 asm_exc_page_fault, 由汇编语言完成,除了保存现场外,它还会从栈中获得 error_code, 然后调用 exc_page_fault函数。 后者读取 cr2 寄存器得到导致异常的虚拟地址,然后调用 handle_page_fault。
handle_mm_fault调用_handl_mm_fault继续处理异常,深入分析之前, 我们需要先明确现状、 目标、面临的问题和对策。 现状是我们已经找到了address所属的vma, 目标是完成address所需的映射。 面临的问题可以分为三种类型。
  1. 没有完整的内存映射, 也就是没有映射物理内存,申请物理内存完成映射即可。
  2. 映射究整,但物埋页已经被交换出去,需要将原来的内容读入内存, 完成映射。
  3. 映射完整,内存映射为可写,页表为只读,写内存导致异常,常见的情况就是COW。
用户空间虚拟内存访问权限分为两部分,一部分体现在vma->vm_flags 中(VM_READ、VM_EXEC
和VM_WRlTE等), 另一部分存储在页表中。

malloc

大家都知道 malloc 是用来申请堆内存的
  1. 堆内存接着bss段存放,中间有一个页对齐
  2. 堆内存是由glibc管理的,每次调用brk改变堆内存的大小
  3. malloc返回后,得到的是虚拟地址,不一定有物理地址与之的对应,缺页异常申请物理内存。

内存回收调用栈

_alloc_pages_slowpath在内存分配的过程中起到了不可替代的作用,在在get_page_from_freelist失败的情况下被执行,进行内存回收,调用栈如下:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值