0Pricing
C++ Academy · 课时

协程帧分配

分析协程帧的分配方式和生命周期

协程帧分配 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。

状态存放在哪里

协程中的局部变量会跨越挂起而继续存在。它们不能存放在栈上——函数会在两次挂起之间返回。因此,它们存放在堆上分配的协程帧中。

帧中包含什么

帧中包含:

  • 协程的参数
  • 承诺对象
  • 跨越挂起而继续存在的局部变量
  • 恢复和销毁函数指针

堆分配的开销

每次调用协程都会分配一个帧。分配并非没有成本——对于高频协程来说,这一点尤其重要。优化编译器可能在生命周期有明确边界时省略这次分配,这称为 HALO(堆分配 eLision 优化)。

HALO 何时生效

在以下情况下,编译器可能避免堆分配:

  • 能够证明协程的生命周期被限制在某个范围内
  • 内联可以证明帧适合放在栈上
  • 帧大小在编译时固定

自定义分配器

您可以在 promise_type 内重载 operator new,为协程帧提供自定义分配器。

struct promise_type {
    void* operator new(size_t size) {
        return std::malloc(size);
    }
    void operator delete(void* ptr) {
        std::free(ptr);
    }
};

帧池

对于高吞吐量的异步系统,可以从池中分配帧,以避免通用分配器的开销。每个线程或任务类型都可以拥有自己的池。

帧大小

帧大小取决于任一挂起点上可能仍然存活的最大变量集合。增加更多局部变量会增大帧的大小。

减小帧大小

建议:

  • 严格限制变量的作用域
  • 避免使用大型局部数组——明确使用堆
  • 将临时变量移入独立的非协程辅助函数

检查帧

编译器可以输出帧大小。使用 clang 时,启用 -fcoro-aligned-allocation,并通过诊断选项进行检查。反汇编可以揭示帧的布局。

生命周期与清理

当 final_suspend 执行完毕时,协程帧会被销毁(如果显式销毁,也可能更早销毁)。RAII 成员会被正确析构。

内存安全

协程句柄是一个原始指针。协程销毁后仍然持有句柄会导致未定义行为。库类型使用 RAII 封装句柄,以避免这种情况。

何时需要关注

大多数应用程序完全不需要考虑帧分配。只有在拥有数百万个协程或面临极高的性能要求时才需要关注。请先进行性能分析。

快速检查

为什么协程帧通常存放在堆上?

回顾

协程会分配堆帧,以便在挂起期间保留状态。在可行时,编译器可以省略分配(HALO)。自定义分配器和帧池有助于构建高吞吐量系统,但大多数代码无需对此操心。

常见问题解答

「协程帧分配」课时是免费的吗?

是的 — 「协程帧分配」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。

「协程帧分配」这节课中我会学到什么?

分析协程帧的分配方式和生命周期 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C++ Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「协程帧分配」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C++ Academy 课中编写并运行代码吗?

能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 协程概念:co_await、co_yield、co_return
  2. 实现一个简单的生成器
  3. 异步任务与等待器类型
  4. 协程帧分配
← 返回 C++ Academy