前言

内核不仅需要管理虚拟内存,还需要管理具体的物理内存。

先简单介绍一下两个概念,一致性内存访问(Uniform Memory Access, UMA)和非一致性内存访问(Non-uniform Memory Access),前者表示同一个CPU对所有内存访问速度一致,后者则表示不一致。CPU通过总线访问内存,如果CPU过多,前者其实是所有CPU-总线-所有内存,后者就变成CPU-专用内存,速度会快很多,如果专用内存不够,就可以通过总线访问其他专用内存。

本文不涉及到具体的分页,只涉及到了交换内存

交换内存

内存回收

应用程序读取到某个虚拟内存,CPU就会去寻址物理内存,如果还没有映射到物理内存,就会发出缺页中断,进程就会切换到内核态,调用内核的Page Fault Handler(缺页中断函数)处理。

缺页中断函数会检查是否有空间物理内存,有的话直接分配,没有的话就需要回收内存了。

  • 后台回收内存(kswapd):通过kswapd内核线程来回收,并且是异步的,在后台运行。
  • 直接内存回收(direct reclaim):如果内存不够,会调用直接内存回收,同步进行,并且会阻塞用户进程。

如果内存回收后,空闲内存害不够满足此次内存申请,就会触发超内存机制(Out of Memory, OOM),它会kill掉占用内存较高的进程,知道足够的物理内存被释放。

如果是文件页,内存就会直接直接释放,或者写入后释放。如果是匿名页,那就是通过swap(交换内存)机制,写入磁盘交换分区中,通常采用LRU算法回收,回收掉不活跃的页。

页面置换调度算法

  • 最佳页面置换算法(OPT)

    预知每一个页面在未来的访问频率,选择置换,但是在现实中不可能实现,所以预测越准,效率越高

  • 先进先出置换算法(FIFO)

    置换出滞留最久的页面,使用一个队列即可完成,性能不佳

  • 最近最久未使用置换算法(LRU)

    选择最常时间未使用的页面进行置换,代价还是比较高的,需要维护一个序列,对未使用时间进行降序

  • 时钟页面置换算法(Lock)

    结合了LRU和FIFO算法

    维护一个环形链表,链表项记录着页号,访问位,物理页号,如果需要置换:

    一个指针指向某个页表,访问位为1,则置为0并前移表针,访问位为0,则在此进行内存交换(新表置1),表针前移一个.

  • 最不常用置换算法(LFU)

    置换掉访问次数最小的,但是这个只考虑了频率,没有考虑时间,有可能过去常常访问,但是后续都不太可能访问的页面会占据内存。

    解决方法之一:定期减少访问的记录,比如把所有页面的访问次数除半