从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 跨节点访问的时候,也会出现放大。