x/website/_content/doc: add note about how much memory the Go runtime retains to the GC guide

eimct9ow  于 9个月前  发布在  Go
关注(0)|答案(5)|浏览(107)

你好,
我花了很多时间去寻找一个并不存在的“内存泄漏”的原因。这是因为我们对内存管理存在根本性的误解。我们认为垃圾回收器会将未使用的堆内存返回给操作系统,这是错误的。
解释在#41444(评论)中:
"由于Go垃圾回收器的设计是保留大约两倍于活动堆大小的内存,因此debug.FreeOSMemory预计可以释放大约一半的内存"
你能否将这些信息添加到https://tip.golang.org/doc/gc-guide中?
我认为了解这一点非常重要。

hsgswve4

hsgswve41#

这部分内容原本是打算在 https://tip.golang.org/doc/gc-guide#GOGC 中解释的,尽管那一部分文字较多,可能可以更直接、简洁地提及总堆大小。

66bbxpm5

66bbxpm52#

我们认为垃圾回收器将未使用的堆内存返回给操作系统,这是错误的。
澄清一下,它确实将未使用的堆内存返回给操作系统,但它不会将内存返回给它认为在不久的将来会使用的操作系统。它通常会保留足够的内存供应用程序分配到下一个堆目标(runtime.MemStats.NextGC,或runtime/metrics度量/gc/heap/goal:bytes),而无需操作系统分页进入新的物理内存,这很昂贵。
我认为(但不确定)这就是你看到的。
"由于Go垃圾回收器的设计是保留大约两倍于活动堆大小的内存,因此debug.FreeOSMemory预计可以释放大约一半的内存"
这句话是正确的,但其中有很多细微之处。如果你的应用程序定期分配内存,debug.FreeOSMemory可能会看起来几乎没有效果,因为结果将是短暂的。正如奥斯汀在您链接的评论中指出的那样,活跃的应用程序很快就会再次使用这些内存。当你期望应用程序长时间处于空闲状态时,这种情况就更有意义了。同时,调用debug.FreeOSMemory可能会产生大量的CPU成本。如果你的应用程序处于活动状态,那么刚刚释放给操作系统的内存很可能会被立即分页,正如我上面提到的,这是昂贵的。它还强制执行完整的GC周期,增加GC频率。
debug.FreeOSMemory应该放在GC指南中,但我尽量避免推荐debug.FreeOSMemory,因为它真的是最后的手段。
这个解释应该在https://tip.golang.org/doc/gc-guide#GOGC中解释,尽管该部分有更多的文字和可能更直接、简洁地提及总堆大小。
顺便说一下,总堆大小在一个句子中定义,位于该部分的顶部。重新阅读该部分,大部分文本似乎都是脚注和示例(即“可以用来关闭GC”,“Go 1.18做了......”,“这里有一个例子”,“这里有如何使用交互式示例”)。将所有这些放在一起确实会让一个人的眼睛发呆。我承认我们可以通过将脚注移动到实际的脚注中并将示例放在“示例”子标题下使这个过程变得更好。我认为如果在第几句话后停止阅读定义本身是可以接受的。
这并没有真正解决“眼睛发呆”的问题,但我认为这里可能缺少的是一句像“GC始终为应用程序分配足够的内存以达到目标堆大小”这样的简短句子。也许如果我们重新组织该部分,额外的句子就不会那么糟糕了。

lbsnaicq

lbsnaicq3#

我的应用程序按需分配内存,例如在收到Web请求时。令人烦恼的是,它不会将所有已使用的内存返回给操作系统,无论我们等待多长时间。因此,从操作系统的Angular 来看,内存使用量没有恢复到我们在发出Web请求之前的水平。
对我来说,返回的确切数量并不重要,但事实是它没有返回所有空闲内存。老实说,我对gc-guide的理解只是部分的。也许这就是为什么从操作系统的Angular 来看,最终结果对我来说并不明确的原因。
无论如何,我已经确保内存使用量不会随着时间的推移而不断增加。这运行得很好。

q5iwbnjs

q5iwbnjs4#

令人烦恼的是,它不会将所有已使用的内存返回给操作系统,无论我们等待多长时间。出于好奇,你等了多久?如果没有更早地运行,每2分钟就会强制进行一次垃圾回收。一旦发生这种情况,后台清理程序应该逐渐将内存返回给操作系统。

zyfwsgd6

zyfwsgd65#

我等了两天。
也许附上的图表有所帮助。

我认为图表显示的内容与top命令中的RES列相同。
昨天部署了两个示例的模块,它们最初消耗的内存量相同。在经过一些负载后,绿色的pod始终比黄色的pod使用更多的内存,即使在一整晚几乎没有活动的情况下也是如此。
今天早上我在07:35-07:38之间产生了一些负载。您可以看到两个pod的内存使用率都没有恢复到原始水平。这就是我们最初解释为内存泄漏的原因。
我已经90%确定我们没有真正的内存泄漏,因为几天前我为两个小时的时间创建了大量的负载,其中内存使用量很高,但并没有持续增加。我的老板有95%的把握 😃
绿色pod在08:45收集的度量指标(不确定它们是否有帮助):

  1. go_gc_duration_seconds{quantile="0"} 7.4805e-05
  2. go_gc_duration_seconds{quantile="0.25"} 0.000113463
  3. go_gc_duration_seconds{quantile="0.5"} 0.000141882
  4. go_gc_duration_seconds{quantile="0.75"} 0.000211009
  5. go_gc_duration_seconds{quantile="1"} 0.086942859
  6. go_gc_duration_seconds_sum 0.379772665
  7. go_gc_duration_seconds_count 615
  8. go_goroutines 562
  9. go_info{version="go1.21.5"} 1
  10. go_memstats_alloc_bytes 5.6752192e+07
  11. go_memstats_alloc_bytes_total 1.3669962256e+10
  12. go_memstats_buck_hash_sys_bytes 1.633549e+06
  13. go_memstats_frees_total 1.76503274e+08
  14. go_memstats_gc_sys_bytes 6.688632e+06
  15. go_memstats_heap_alloc_bytes 5.6752192e+07
  16. go_memstats_heap_idle_bytes 3.3284096e+07
  17. go_memstats_heap_inuse_bytes 6.6985984e+07
  18. go_memstats_heap_objects 408825
  19. go_memstats_heap_released_bytes 2.1897216e+07
  20. go_memstats_heap_sys_bytes 1.0027008e+08
  21. go_memstats_last_gc_time_seconds 1.7048726598582582e+09
  22. go_memstats_lookups_total 0
  23. go_memstats_mallocs_total 1.76912099e+08
  24. go_memstats_mcache_inuse_bytes 31200
  25. go_memstats_mcache_sys_bytes 31200
  26. go_memstats_mspan_inuse_bytes 1.108128e+06
  27. go_memstats_mspan_sys_bytes 1.450344e+06
  28. go_memstats_next_gc_bytes 8.9540592e+07
  29. go_memstats_other_sys_bytes 4.704587e+06
  30. go_memstats_stack_inuse_bytes 4.58752e+06
  31. go_memstats_stack_sys_bytes 4.58752e+06
  32. go_memstats_sys_bytes 1.19365912e+08
  33. go_threads 30
  34. process_cpu_seconds_total 3805.21
  35. process_max_fds 1.048576e+06
  36. process_open_fds 145
  37. process_resident_memory_bytes 1.21344e+08
  38. process_start_time_seconds 1.70480085494e+09
  39. process_virtual_memory_bytes 1.365942272e+09
  40. process_virtual_memory_max_bytes 1.8446744073709552e+19
  41. promhttp_metric_handler_requests_in_flight 1
  42. promhttp_metric_handler_requests_total{code="200"} 2396
  43. promhttp_metric_handler_requests_total{code="500"} 0
  44. promhttp_metric_handler_requests_total{code="503"} 0
展开查看全部

相关问题