🐱 猫头虎博主来啦!今天带来的是Go语言的最新动态。如果你是一个Go语言爱好者,那这篇文章一定不容错过!一起来看看自2018年以来Go运行时和Go垃圾收集器(GC)有哪些新的变化吧!🚀
🔍 在这篇文章中,作为猫头虎博主,我将带大家深入探讨自2018年以来Go运行时的发展。从sync.Pool
的优化,内存分配器的改进,到新的软内存限制功能,我们将深入每一个更新,了解它们是如何使Go语言变得更高效。准备好了吗?让我们开始吧!
自2018年我们关于Go GC的上一篇博客以来,Go运行时和Go垃圾收集器(GC)有了稳步的提升。这些改进主要是为了应对现实世界中Go程序的挑战和Go用户面临的实际问题。接下来,让我们一起回顾这些年来的亮点吧!
sync.Pool
的优化defer
语句的优化defer
声明的函数调用现在在大多数情况下的成本与常规函数调用一样低。点击此处观看Gophercon 2020的演讲。(Go 1.14).go.dev/runtime/metrics)。这降低了获取运行时统计数据的延迟两个数量级(从毫秒到微秒)。(Go 1.16)
随着Go 1.19的发布,一个期待已久的特性终于来了:Go运行时的软内存限制。
多年来,Go GC只有一个调节参数:GOGC
。GOGC
让用户调整由Go GC做出的CPU开销与内存开销之间的权衡。这个“调节器”长期以来服务于Go社区,涵盖了广泛的用例。
为什么要添加一个内存限制调节器呢?
内存与CPU时间不同,不像CPU时间那样总有未来可以等待。但对于内存来说,有一个极限。
内存限制解决了两个问题。
首先,当应用程序的峰值内存使用不可预测时,仅靠GOGC
几乎无法防止内存耗尽。仅有GOGC
时,Go运行时根本不知道它能使用多少内存。设置内存限制使得运行时能够抵抗瞬时的、可恢复的负载峰值,通过意识到何时需要更努力地减少内存开销。
其次,为了在不使用内存限制的情况下避免内存不足错误,必须根据峰值内存调整GOGC
,即使在应用程序不在峰值内存使用时也保持低内存开销,从而导致更高的GC CPU开销。这在我们这个容器化的世界尤为重要,程序被放置在具有特定和隔离的内存预留的箱子中;我们可能会更好地利用它们!通过提供对负载峰值的保护,设置内存限制允许GOGC
在CPU开销方面进行更积极的调整。
内存限制的设计旨在易于采用和鲁棒。例如,它是对应用程序Go部分的整个内存占用的限制,而不仅仅是Go堆,所以用户不必担心计算Go运行时的开销。运行时也会根据内存限制调整其内存清理政策,以便在面对内存压力时更积极地将内存返回给操作系统。
然而,尽管内存限制是一个强大的工具,但在使用时仍需小心。一个重要的注意事项是,它可能导致程序出现GC抖动:程序花费太多时间运行GC,导致无法有效地进行实质性工作。例如,如果为Go程序设置的内存限制过低,不足以满足程序实际所需的内存,那么程序可能会出现抖动。以前,除非GOGC
被明确调整为更偏重于内存使用,否则GC抖动是不太可能发生的。作为一种缓解措施,即使这意味着超出内存限制,运行时也会将GC限制在总CPU时间的50%以内。
考虑到这些,我们发布了一份全新的GC指南,其中包含互动式可视化内容,帮助您理解GC成本以及如何操纵它们。
尝试使用内存限制!在生产环境中使用它!阅读GC指南!
我们一直在寻求反馈,以改进Go,但同时也希望听到关于它如何有效工作的故事。发送我们反馈!
特性 | 描述 | Go版本 |
---|---|---|
sync.Pool优化 | 低延迟影响,高效内存回收 | Go 1.13 |
主动回收内存 | 减少内存消耗,降低内存不足错误 | Go 1.13, 1.14 |
Goroutine抢占 | 减少停止世界延迟 | Go 1.14 |
定时器管理 | 在多核CPU上效率更高 | Go 1.14 |
defer优化 | 成本接近常规函数调用 | Go 1.14 |
内存分配器 | 更好的CPU核心扩展性 | Go 1.14, 1.15 |
内存统计API | 更快的运行时统计数据访问 | Go 1.16 |
调度器CPU优化 | 减少CPU时间消耗 | Go 1.17 |
基于寄存器的调用约定 | 提高CPU效率 | Go 1.17, 1.18 |
GC内部重设计 | 减少尾延迟,提高效率 | Go 1.18 |
限制GC的CPU使用 | 减少CPU利用率 | Go 1.19 |
以上就是自2018年以来Go运行时的主要进展。这些改进大多对用户来说是不可见的:他们熟悉和喜爱的Go代码,只需升级Go版本就能运行得更好。