返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

3.2.1 阈值属性

发布于 2024-10-12 19:16:03 字数 2852 浏览 0 评论 0 收藏 0

与 GC 相关的内存数据由 memstats 记录,其中与垃圾回收有关的重点字段如下:

  • next_gc : 预期下次回收启动时,已分配堆大小。
  • gc_trigger : 实际触发阈值,通常要小于预期值。
  • triggerRatio : 由控制器根据回收周期内统计数据计算得出,用于调整阈值比率。
  • heap_marked : 标记结束后,存活对象大小总和。
  • gcpercent : 环境变量 GOGC 值(默认 100),调整最小堆和比率上限。

triggerRatio、heap_marked 默认值在 gcinit 里设定。

triggerRatio

在相关函数(setGCPercent、gcSetTriggerRatio)里能找到计算公式。

heapminimum     = defaultHeapMinimum * gcpercent / 100
maxTriggerRatio = 0.95 * gcpercent / 100

gc_trigger      = heap_marked * (1 + triggerRatio)    // 0.6 <= triggerRatio <= 0.95
next_gc         = heap_marked + heap_marked * gcpercent/100

trigger 和 goal 默认值 ^0 是个无法达到的值(18446744073709551615)。

如果 GOGC < 0,那么阈值无法触发,从而变相阻止垃圾回收启动。

标记结束(gcMarkDone)时,调用 gcControllerState.endCycle 计算阈值比率。

// mgc.go

func gcSetTriggerRatio(triggerRatio float64) {
    
    // 预期目标值。
    goal := ^uint64(0)
    if gcpercent >= 0 {
        goal = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100
    }
    
    // 设置回收比率(0.6 <= ? <= 0.95)。
    const minTriggerRatio = 0.6
    if triggerRatio < minTriggerRatio {
        triggerRatio = minTriggerRatio
    } else if gcpercent >= 0 {
        maxTriggerRatio := 0.95 * float64(gcpercent) / 100
        if triggerRatio > maxTriggerRatio { triggerRatio = maxTriggerRatio }
    }
    
    memstats.triggerRatio = triggerRatio
    
    // 通过比率计算绝对触发阈值。
    trigger := ^uint64(0)
    if gcpercent >= 0 {
        trigger = uint64(float64(memstats.heap_marked) * (1 + triggerRatio))
        
        // 最小、最大范围。
        minTrigger := heapminimum
        if trigger < minTrigger { trigger = minTrigger }
        if trigger > goal { goal = trigger }
    }
    
    memstats.gc_trigger = trigger
    memstats.next_gc = goal
}

gcpercent

环境变量 GOGC 是除强制回收函数外,对垃圾回收的唯一干预手段。

GOGC 百分比数值参与阈值比率计算,进而影响回收触发时机。

1. < 0 :(off),关闭垃圾回收。

2. > 0 : 增大垃圾回收阈值,延迟回收。

3. 默认 100,表示阈值接近当前标记结果的两倍。

调用 runtime.GC 强制执行垃圾回收,不受 GOGC 和阈值限制。

但该函数会阻塞用户逻辑执行,直至回收完全结束。

// mgc.go

func readgogc() int32 {
    p := gogetenv("GOGC")
    
    if p == "off" {
        return -1
    }
    
    if n, ok := atoi32(p); ok {
        return n
    }
    
    return 100
}
func setGCPercent(in int32) (out int32) {
    
    // 当前值,用于返回。
    out = gcpercent
    
    if in < 0 {
        in = -1
    }
    
    gcpercent = in
    heapminimum = defaultHeapMinimum * uint64(gcpercent) / 100
    
    // 设置阈值和比率。
    gcSetTriggerRatio(memstats.triggerRatio)
    
    return out
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文