热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

用GODEBUG看GC

什么是GC在计算机科学中,垃圾回收(GC)是一种自动管理内存的机制,垃圾回收器会去尝试回收程序不再使用的对象及其占用的内存。

640?wx_fmt=png

什么是 GC

在计算机科学中,垃圾回收(GC)是一种自动管理内存的机制,垃圾回收器会去尝试回收程序不再使用的对象及其占用的内存。而最早 John McCarthy 在 1959 年左右发明了垃圾回收,以简化 Lisp 中的手动内存管理的机制(来自 wikipedia)。

为什么要 GC

手动管理内存挺麻烦,管错或者管漏内存也很糟糕,将会直接导致程序不稳定(持续泄露)甚至直接崩溃。

GC 带来的问题

硬要说会带来什么问题的话,也就数大家最关注的 Stop The World(STW),STW 代指在执行某个垃圾回收算法的某个阶段时,需要将整个应用程序暂停去处理 GC 相关的工作事项。例如:

行为会不会 STW为什么
标记开始在开始标记时,准备根对象的扫描,会打开写屏障(Write Barrier) 和 辅助GC(mutator assist),而回收器和应用程序是并发运行的,因此会暂停当前正在运行的所有 Goroutine。
并发标记中不会标记阶段,主要目的是标记堆内存中仍在使用的值。
标记结束在完成标记任务后,将重新扫描部分根对象,这时候会禁用写屏障(Write Barrier)和辅助GC(mutator assist),而标记阶段和应用程序是并发运行的,所以在标记阶段可能会有新的对象产生,因此在重新扫描时需要进行 STW。

如何调整 GC 频率

可以通过 GOGC 变量设置初始垃圾收集器的目标百分比值,对比的规则为当新分配的数值与上一次收集后剩余的实时数值的比例达到设置的目标百分比时,就会触发 GC,默认值为 GOGC=100。如果将其设置为 GOGC=off 可以完全禁用垃圾回收器,要不试试?

简单来讲就是,GOGC 的值设置的越大,GC 的频率越低,但每次最终所触发到 GC 的堆内存也会更大。

各版本 GC 情况

版本GC 算法STW 时间
Go 1.0STW(强依赖 tcmalloc)百ms到秒级别
Go 1.3Mark STW, Sweep 并行百ms级别
Go 1.5三色标记法, 并发标记清除。同时运行时从 C 和少量汇编,改为 Go 和少量汇编实现10-50ms级别
Go 1.61.5 中一些与并发 GC 不协调的地方更改,集中式的 GC 协调协程,改为状态机实现5ms级别
Go 1.7GC 时由 mark 栈收缩改为并发,span 对象分配机制由 freelist 改为 bitmap 模式,SSA引入ms级别
Go 1.8混合写屏障(hybrid write barrier), 消除 re-scanning stacksub ms
Go 1.12Mark Termination 流程优化sub ms, 但几乎减少一半

注:资料来源于 @boya 在深圳 Gopher Meetup 的分享。

GODEBUG

GODEBUG 变量可以控制运行时内的调试变量,参数以逗号分隔,格式为:name=val。本文着重点在 GC 的观察上,主要涉及 gctrace 参数,我们通过设置 gctrace=1 后就可以使得垃圾收集器向标准错误流发出 GC 运行信息。

涉及术语

  • mark:标记阶段。

  • markTermination:标记结束阶段。

  • mutator assist:辅助 GC,是指在 GC 过程中 mutator 线程会并发运行,而 mutator assist 机制会协助 GC 做一部分的工作。

  • heaplive:在 Go 的内存管理中,span 是内存页的基本单元,每页大小为 8kb,同时 Go 会根据对象的大小不同而分配不同页数的 span,而 heaplive 就代表着所有 span 的总大小。

  • dedicated / fractional / idle:在标记阶段会分为三种不同的 mark worker 模式,分别是 dedicated、fractional 和 idle,它们代表着不同的专注程度,其中 dedicated 模式最专注,是完整的 GC 回收行为,fractional 只会干部分的 GC 行为,idle 最轻松。这里你只需要了解它是不同专注程度的 mark worker 就好了,详细介绍我们可以等后续的文章。

演示代码

func main() { wg :&#61; sync.WaitGroup{} wg.Add(10) for i :&#61; 0; i <10; i&#43;&#43; { go func(wg *sync.WaitGroup) { var counter int for i :&#61; 0; i <1e10; i&#43;&#43; { counter&#43;&#43; } wg.Done() }(&wg) } wg.Wait()
}

gctrace

$ GODEBUG&#61;gctrace&#61;1 go run main.go
gc 1 &#64;0.032s 0%: 0.019&#43;0.45&#43;0.003 ms clock, 0.076&#43;0.22/0.40/0.80&#43;0.012 ms cpu, 4->4->0 MB, 5 MB goal, 4 P
gc 2 &#64;0.046s 0%: 0.004&#43;0.40&#43;0.008 ms clock, 0.017&#43;0.32/0.25/0.81&#43;0.034 ms cpu, 4->4->0 MB, 5 MB goal, 4 P
gc 3 &#64;0.063s 0%: 0.004&#43;0.40&#43;0.008 ms clock, 0.018&#43;0.056/0.32/0.64&#43;0.033 ms cpu, 4->4->0 MB, 5 MB goal, 4 P
gc 4 &#64;0.080s 0%: 0.004&#43;0.45&#43;0.016 ms clock, 0.018&#43;0.15/0.34/0.77&#43;0.065 ms cpu, 4->4->1 MB, 5 MB goal, 4 P
gc 5 &#64;0.095s 0%: 0.015&#43;0.87&#43;0.005 ms clock, 0.061&#43;0.27/0.74/1.8&#43;0.023 ms cpu, 4->4->1 MB, 5 MB goal, 4 P
gc 6 &#64;0.113s 0%: 0.014&#43;0.69&#43;0.002 ms clock, 0.056&#43;0.23/0.48/1.4&#43;0.011 ms cpu, 4->4->1 MB, 5 MB goal, 4 P
gc 7 &#64;0.140s 1%: 0.031&#43;2.0&#43;0.042 ms clock, 0.12&#43;0.43/1.8/0.049&#43;0.17 ms cpu, 4->4->1 MB, 5 MB goal, 4 P
...

格式

gc # &#64;#s #%: #&#43;#&#43;# ms clock, #&#43;#/#/#&#43;# ms cpu, #->#-># MB, # MB goal, # P

含义

  • gc#&#xff1a;GC 执行次数的编号&#xff0c;每次叠加。

  • &#64;#s&#xff1a;自程序启动后到当前的具体秒数。

  • #%&#xff1a;自程序启动以来在GC中花费的时间百分比。

  • #&#43;...&#43;#&#xff1a;GC 的标记工作共使用的 CPU 时间占总 CPU 时间的百分比。

  • #->#-># MB&#xff1a;分别表示 GC 启动时, GC 结束时, GC 活动时的堆大小.

  • #MB goal&#xff1a;下一次触发 GC 的内存占用阈值。

  • #P&#xff1a;当前使用的处理器 P 的数量。

案例

gc 7 &#64;0.140s 1%: 0.031&#43;2.0&#43;0.042 ms clock, 0.12&#43;0.43/1.8/0.049&#43;0.17 ms cpu, 4->4->1 MB, 5 MB goal, 4 P

  • gc 7&#xff1a;第 7 次 GC。

  • &#64;0.140s&#xff1a;当前是程序启动后的 0.140s。

  • 1%&#xff1a;程序启动后到现在共花费 1% 的时间在 GC 上。

  • 0.031&#43;2.0&#43;0.042 ms clock&#xff1a;

  • 0.031&#xff1a;表示单个 P 在 mark 阶段的 STW 时间。

  • 2.0&#xff1a;表示所有 P 的 mark concurrent&#xff08;并发标记&#xff09;所使用的时间。

  • 0.042&#xff1a;表示单个 P 的 markTermination 阶段的 STW 时间。

  • 0.12&#43;0.43/1.8/0.049&#43;0.17 ms cpu&#xff1a;

  • 0.12&#xff1a;表示整个进程在 mark 阶段 STW 停顿的时间。

  • 0.43/1.8/0.049&#xff1a;0.43 表示 mutator assist 占用的时间&#xff0c;1.8 表示 dedicated &#43; fractional 占用的时间&#xff0c;0.049 表示 idle 占用的时间。

  • 0.17ms&#xff1a;0.17 表示整个进程在 markTermination 阶段 STW 时间。

  • 4->4->1 MB&#xff1a;

  • 4&#xff1a;表示开始 mark 阶段前的 heap_live 大小。

  • 4&#xff1a;表示开始 markTermination 阶段前的 heap_live 大小。

  • 1&#xff1a;表示被标记对象的大小。

  • 5 MB goal&#xff1a;表示下一次触发 GC 回收的阈值是 5 MB。

  • 4 P&#xff1a;本次 GC 一共涉及多少个 P。

总结

通过本章节我们掌握了使用 GODEBUG 查看应用程序 GC 运行情况的方法&#xff0c;只要用这种方法我们就可以观测不同情况下 GC 的情况了&#xff0c;甚至可以做出非常直观的对比图&#xff0c;大家不妨尝试一下。

关联文章

参考

  • Go GC打印出来的这些信息都是什么含义&#xff1f;

  • GODEBUG之gctrace解析

  • 关于Golang GC的一些误解--真的比Java GC更领先吗&#xff1f;

  • &#64;boya 深入浅出Golang Runtime PPT



推荐阅读
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • 生产环境下JVM调优参数的设置实例
     正文前先来一波福利推荐: 福利一:百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。福利二 ... [详细]
  • Python中程序员的面试题有哪些
    小编给大家分享一下Python中程序员的面试题有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有 ... [详细]
  • 数据结构与算法习题replacementselectionsort(置换选择排序)TimeLimit:1000msMemoryLimit:65536kBDescrip ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文介绍了Java的集合及其实现类,包括数据结构、抽象类和具体实现类的关系,详细介绍了List接口及其实现类ArrayList的基本操作和特点。文章通过提供相关参考文档和链接,帮助读者更好地理解和使用Java的集合类。 ... [详细]
  • 网卡工作原理及网络知识分享
    本文介绍了网卡的工作原理,包括CSMA/CD、ARP欺骗等网络知识。网卡是负责整台计算机的网络通信,没有它,计算机将成为信息孤岛。文章通过一个对话的形式,生动形象地讲述了网卡的工作原理,并介绍了集线器Hub时代的网络构成。对于想学习网络知识的读者来说,本文是一篇不错的参考资料。 ... [详细]
author-avatar
手机用户2602904731
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有