动态内存管理

动态内存管理

2024 南京大学《操作系统:设计与实现》
动态内存管理

内存分配:操作系统的机制

大段内存,要多少有多少

  • 用 MAP_ANONYMOUS 申请,想多少就有多少
    • 超过物理内存上限都行 (Demo)

反而,操作系统不支持分配一小段内存

  • 这是应用程序自己的事
  • malloc() 和 free()
    • Specification 很简单:Lab1
    • 在大区间 [L,R)[L, R) 中维护互不相交的区间的集合
  • 麻烦:多线程安全和 scalability
2024 南京大学《操作系统:设计与实现》
动态内存管理

实现高效的 malloc/free

Premature optimization is the root of all evil.

——D. E. Knuth

重要的事情说三遍:

  • 脱离 workload 做优化就是耍流氓
    • 在开始考虑性能之前,理解你需要考虑什么样的性能

然后,去哪里找 workload?

2024 南京大学《操作系统:设计与实现》
动态内存管理

理论 v.s. 实践

在实际系统中,我们通常不考虑 adversarial worst case

  • 现实中的应用是 “正常” 的,不是 “恶意” 的

malloc() 的观察

  • 大对象分配后应,读写数量应当远大于它的大小
    • 否则就是 performance bug
    • 申请 16MB 内存,扫了一遍就释放了😂
      • 这不是 bug,难道还是 feature 吗?
  • 推论:越小的对象创建/分配越频繁
2024 南京大学《操作系统:设计与实现》
动态内存管理

malloc() 的观察

我们需要管理的对象

  • 小对象:字符串、临时对象等;生存周期可长可短
  • 中对象:容器、复杂的对象;更长的生存周期
  • 大对象:巨大的容器、分配器;很长的生存周期

结论

  • 我们几乎只要管好小对象就好了 (当然,仅针对 oslabs)
  • 由于所有分配都会在所有处理器上发生
    • 小对象分配/回收的 scalability 是主要瓶颈
    • 使用链表/区间树 (first fit) 可不是个好想法
2024 南京大学《操作系统:设计与实现》
动态内存管理

malloc, Fast and Slow

人类也是这样的系统

  • Thinking, Fast and Slow by Daniel Kahneman

设置两套系统

  • Fast path (System I) ← AI 已经开始超越 System I 人类
    • 性能极好、并行度极高、覆盖大部分情况
    • 但有小概率会失败 (fall back to slow path)
  • Slow path (System II) ← 预计很快就要失守
    • 不在乎那么快
    • 但把困难的事情做好
  • 计算机系统里有很多这样的例子 (比如 cache)
2024 南京大学《操作系统:设计与实现》
动态内存管理

malloc: Fast Path 设计

浪费一点空间,但使所有 CPU 都能并行地申请内存

  • 线程都事先瓜分一些 “领地” (thread-local allocation buffer)
  • 默认从自己的领地里分配
    • 除了在另一个 CPU 释放,acquire lock 几乎总是成功
  • 如果自己的领地不足,就从全局的池子里借一点

System 人的智慧:不要在乎浪费

  • 这就是为什么要对齐到 2k2^k 字节
2024 南京大学《操作系统:设计与实现》
动态内存管理

小内存:Segregated List

center

分配: Segregated List (Slab)

  • 每个 slab 里的每个对象都一样大
    • 每个线程拥有每个对象大小的 slab
    • fast path → 立即在线程本地分配完成
    • slow path → pgalloc()
2024 南京大学《操作系统:设计与实现》
动态内存管理

小内存:Segregated List (cont'd)

分配: Slab

  • 问题被简化了
    • 一个内存页被分配成大小是 2k2^k 的分配单元
    • 每个分配单元里塞个指针,就是 free list 了
    • (uintptr_t)p & 0xfff 就可以得到对应的 slab
      • 头部可以存放一些 metadata,例如自旋锁

回收:直接归还到 slab 中

  • 注意这可能是另一个线程持有的 slab
  • 需要 per-slab 锁 (小心数据竞争)
2024 南京大学《操作系统:设计与实现》
动态内存管理

大内存:一把大锁保平安

Buddy system (1963)

  • 如果你想分配 1, 2, 3, 4, ... nn 个连续的页面?
    • 例如:64 KB/页面
  • 那就 first fit 或者 best fit 吧……

这是一个数据结构问题

  • 区间树;线段树……
2024 南京大学《操作系统:设计与实现》
动态内存管理

现实世界中的 malloc/free 🌶️

center

以上就是所有现代 malloc/free 实现的基础

  • musl: size_classes
  • glibc: arena → heap → tcache (thread-local)
  • mimalloc: free list sharding
  • tcmalloc: thread-caching malloc
2024 南京大学《操作系统:设计与实现》