runtime

主要组成部分:

  • 内存管理
    • 内存分配

      • 使用TCMalloc(thread-cacheing malloc)算法的变体
      • 对象根据大小分为微小对象(0-16B)、小对象(16B-32KB)和大对象(>32KB)。 使用 mspan 结构管理内存页,mcache 为每个 P 提供本地缓存。 内存分配时,会优先从 线程缓存 获取,当 线程缓存 没有足够的内存时,会尝试从 中心缓存 获取,如果申请内存超过 32KB 时,会直接从 页堆 获取。
      • mcentral 用于在不同 mcache 之间平衡内存。
    • 栈管理

      • 使用分段栈(Segmented Stacks)技术,初始栈大小通常为 2KB。
      • 当栈空间不足时,会触发栈扩容,创建新的更大的栈并复制内容。
      • Go 1.4 之后采用连续栈(Contiguous Stacks)来避免 "hot split" 问题。
    • 调度器

      • GMP 模型

        • G(Goroutine):表示一个并发任务。
        • M(Machine):表示操作系统线程。
        • P(Processor):表示调度上下文,用于调度 G 到 M 上执行。 通常情况下,P 的数量等于 GOMAXPROCS。
      • 工作窃取(Work Stealing)算法:

        • 当一个 P 的本地队列为空时,会尝试从其他 P 的队列偷取任务。
        • 保证负载均衡,提高整体性能。
      • 调度过程:

      • 当 G 被创建或变为可运行状态时,会被放入 P 的本地队列或全局队列。

      • M 会从绑定的 P 获取 G 来执行。

      • 如果 G 执行系统调用,M 会与 P 解绑,其他 M 可能会接管该 P。

    • 垃圾回收

      • 三色标记清除算法:

      • 白色:潜在的垃圾对象。

      • 灰色:已被标记但其引用还未被扫描的对象。

      • 黑色:已被标记且其所有引用都已被扫描的对象。

      • 写屏障:

        • 用于在并发标记过程中确保对象不会被错误地回收。
        • 包括插入写屏障和删除写屏障。
    • 并发标记和清除:

      • GC 过程大部分与用户程序并发执行,仅在某些阶段会短暂 STW(Stop The World)。
    • 触发机制:

      • 基于堆大小、分配速率和时间间隔等因素自动触发。
    • 系统调用

      • a. 系统调用包装:
      • Go runtime 对操作系统的系统调用进行了封装。
      • 在进行系统调用时,会解绑 M 和 P,允许其他 G 在该 P 上运行。