内存领域知识

jemalloc 的实现过来的。

OOMKiller

Linux 的 overcommit 机制

  • 如果关闭 overcommit 机制,那么大部分的 OOM 现象将会消失,因为系统分配内存会更加保守
  • 如果开启 overcommit 机制,会根据物理内存、swap 和 overcommit_ratio 判断是否能够分配出内存,依然可能会分配失败
    1
    CommitLimit = [swap size] + [RAM size] * vm.overcommit_ratio / 100

mmap

mmap

几个 flag:

  • MAP_SHARED
  • MAP_SHARED_VALIDATE
  • MAP_PRIVATE
    创建一个 private 的 COW mapping。对这个 mapping 的修改不会对其他进程可见,也不会写到下面的文件里面。
    It is unspecified whether changes made to the file after the mmap() call are visible in the mapped region.

msync

表示从内存刷回到底层文件中。除此之外,只有 munmap 能确保进行这样的刷盘。

  • MS_ASYNC
  • MS_SYNC
  • MS_INVALIDATE
    Asks to invalidate other mappings of the same file (so that they can be updated with the fresh values just written)

madvise

  • MADV_NORMAL
    默认行为,内核根据普通访问模式处理页面。

  • MADV_RANDOM
    随机访问,可能减少 prefetch 操作。

  • MADV_SEQUENTIAL
    顺序访问,可以增加 prefetch。

  • MADV_WILLNEED
    表示该内存区域将在未来使用,内核可以提前加载到内存。

  • MADV_DONTNEED / MADV_FREE / munmap
    三个都是释放内存。后面详细描述。

  • MADV_REMOVE
    从文件映射中移除内存区域,释放物理内存,同时在映射的文件中移除相应内容(需要文件映射)。

  • MADV_DONTFORK
    子进程不会继承该内存区域。

  • MADV_DOFORK

  • MADV_MERGEABLE
    启用内存合并(KSM,Kernel Samepage Merging),允许内核将具有相同内容的内存页面合并以节省内存。

  • MADV_UNMERGEABLE

  • MADV_HUGEPAGE (since Linux 2.6.38)
    表示要去分配一个透明大页,即 Transparent Huge Pages (THP)。

    • 内核会不停扫描,将一段内存变为透明大页
    • 如果分配的地址是对齐的,那么内核可能直接分配为透明大页

    大部分通用的内核都会选择默认开启 THP,而那些嵌入式的系统则可能选择不默认开启。

  • MADV_COLLAPSE
    尽力将普通页面转换为透明大页。

  • MADV_NOHUGEPAGE

  • MADV_SOFT_OFFLINE
    将指定区域中的坏内存页标记为不可用,但不杀死当前进程。

  • MADV_HWPOISON
    强制将页面标记为硬件错误(仅管理员权限可用)。

三个释放内存:

  • munmap
    即时释放物理内存(RSS)以及虚拟地址。
  • MADV_DONTNEED
    即时释放物理内存(RSS)。保留虚拟地址,但可能会造成虚拟地址紧张。
  • MADV_FREE
    延迟释放。

进一步可以参考 https://zhuanlan.zhihu.com/p/570033679。我理解从 munmap 到 MADV_FREE 代价越来越小。

关于透明大页

使用透明大页的缺点:

  • 透明大页的后台进程 khugepaged 在扫描到目标页时,会短暂挂起进程,这会影响内存读写操作的延迟。
  • 在 CoW 时,会产生写放大。
  • 出现 NUMA 跨节点访问的时候,也会出现放大。

PageCache 和缺页中断

NUMA 架构

shm

Reference