Handle 为何比指针更适合 C++

Handles are the better pointers (2018)

在 15 年以上的 C++ 大型项目开发中,我发现过度依赖智能指针会导致严重的性能瓶颈和内存碎片。为了解决这些问题,我采用了一种将内存管理集中化的策略:将同类型对象打包成数组,对外仅暴露 index-handles 而非原始指针。这种方法不仅避免了缓存未命中,还能有效防止内存泄漏和悬空指针。通过将内存操作限制在渲染、物理等核心系统内部,我们既能保持代码的健壮性,又能获得接近原生数组的性能优势。

这种代码在内存损坏方面非常稳健,但在优化方面却慢如蜗牛,因为整个代码充满了缓存未命中。
  1. boricj

    我在嵌入式项目工作中基本就是这么做的。

    对象池,配合索引和代(generations)。这比摆弄原始指针要简单得多,也比 shared_ptr/weak_ptr 开销更小,而且删除对象时不需要清理,因为存储的代号与新对象的代号不匹配。如果你实例化时也递增代号(这样只有偶数代是存活的),甚至可以让它默认可构造,并用 C++ 的高层抽象将其全部隐藏起来。

    不过,我对这些技术的了解来自 2000 年代的游戏架构,像《GTA:罪恶都市》这样的游戏就众所周知地使用了它。

  2. nickwanninger

    我的博士论文就是关于这个主题的,几年前我还发表了一篇 ASPLOS 论文,讲的是通过 LLVM 在托管语言(C/C++)中实现基于 handle 的内存支持:https://nickw.io/papers/asplos24-alaska.pdf

    我们当时观察到的开销令人惊讶地仅仅来自于使用软件 handle 带来的指令和分支开销——我目前正在做硬件实现的工作,开销要低得多。

  3. michaelcampbell

    这篇文章让我(表面上看,这比我经验所及要深得多)想起了最近 Goose 语言是如何组织事物的。

    我从未用过它,但我依稀记得旧的原始 Mac API(基于 Pascal)大量使用了“handle”来解决这个问题,即系统可以在程序不知情的情况下移动分配和内存,表现为“指向<东西>的指针的指针”。大约在 1988/1989 年,我曾埋头研读那些手册,脑海中满是成为一名全职 Mac 开发者的愿景。

同日更多故事

2026-11-03