如今,垃收受接收集者有时光又发清楚明了一个问题,是另一个崩溃。
在这一点上,很天然地就能获得两个结论:要么是硬件有严重的问题,要么在在二进制文件中存在一个严重的内存破坏缺点。 我最初认为第一种情况不太可能,因为这台机械上运行的法度榜样异常杂,没有出现任何不稳定的与硬件有关的迹象。 因为像node_exporter如许的Go二进制文件是静态链接的,不依附于任何其他库,所以我可以下载正式版的二进制文件来试一下。 然而,当我如许做的时刻,法度榜样照样崩溃了。
unexpected fault address 0x0unexpected fault address 0x0fatal error: fault[signal SIGSEGV: segmentation violation code=0x80 addr=0x0 pc=0x76b998]goroutine 13 [running]:runtime.throw(0xabfb11, 0x5) /usr/local/go/src/runtime/panic.go:605 +0x95 fp=0xc420060c40 sp=0xc420060c20 pc=0x42c725runtime.sigpanic() /usr/local/go/src/runtime/signal_unix.go:374 +0x227 fp=0xc420060c90 sp=0xc420060c40 pc=0x443197github.com/prometheus/node_exporter/vendor/github.com/prometheus/client_model/go.(*LabelPair).GetName(...) /go/src/github.com/prometheus/node_exporter/vendor/github.com/prometheus/client_model/go/metrics.pb.go:85github.com/prometheus/node_exporter/vendor/github.com/prometheus/client_golang/prometheus.(*Desc).String(0xc4203ae010, 0xaea9d0, 0xc42045c000) /go/src/github.com/prometheus/node_exporter/vendor/github.com/prometheus/client_golang/prometheus/desc.go:179 +0xc8 fp=0xc420060dc8 sp=0xc420060c90 pc=0x76b998
又是一次完全不合的崩溃。这解释node_exporter的上游或者它的一个依附项确切存在问题,所以,我在GitHub上提交了一个 issue 。也许开辟者以前见过这个,如不雅他们有什么设法主意的话,那么引起他们的留意是异常值得的。
走了一趟并不顺畅的弯路
然后,产生了这个:
这是我用客户的电脑所获得的
哎呀!RAM坏了。更具体点说是有一位(bit)的坏内存。在测试法度榜样完全地运行了一遍之后,最终获得的就只是那一个坏的位,别的在测试7中存在一些误报(在邻近移动块的时刻出来了一个缺点)。
进一步的测试注解,SMP模式下的Memtest86+测试5可以快速检测到缺点,但平日不会在第一遍检测的时刻发明。缺点老是涌如今雷同的地址和雷同的位上。这解释这个问题涌如今一个微弱或泄漏的RAM单位上,特别是随温度会变坏的那种。这异常相符逻辑:温度的升高会增长RAM单位的泄漏,并且很有可能会引起位翻转。
大年夜这个角度来看,这是274,877,906,944个位中的一个坏点。这实际上是一个异常不错的的缺点率了!硬盘和闪存的缺点率要高得多,只是这些设备在出厂时会标出坏块,在用户不知情的情况下透明地换出,并且可以将新发明的弱块透明地标记为坏块,并将其从新定位到备用区。内存并不这么奢跋扈,所以一个坏的位永远都是坏的。
我没有在这台标记本电脑上设备豪华的ECC RAM。然则我拥有将内存坏块标记为坏的才能,并告诉操作体系不要应用它。GRUB 2有一个鲜为人知的功能,它许可你改变传递给启动内核的内存映射。仅仅为了一个坏块而购买新的RAM是不值得的,所以这是一个不错的选择。
memtest86+
舒畅的100°C
我把热风枪设置到一个较低的温度(130°C),并对两个模块进行加热(其他两个模块在后盖下,因为我的标记本电脑总共有四个SODIMM插槽)。我发明别的还有三个弱点只能在高温下才能检测到,它们分布在三个内存条上。
我还发明,即使我交换了模块的地位,产生缺点的地位仍然保持大年夜体上的一致:地址的最高位保持不变。这是因为RAM是交错的:数据遍布在四个内存条上,而不是在每个内存条上持续分派可用地址空间的四分之一。是以,我可以樊篱一个足够大年夜的RAM区域,以覆盖每个缺点位所有可能的地址。我发明,樊篱持续的128KB区域应当足以覆盖每个给定坏点的所有可能的地址分列,然则,为了更好的进行测量,我将它四舍五入到1MB。我用了三个1MB对齐的块来进行掩盖(个一一个块掩盖了两个坏点,我总共要掩盖四个坏点):
- 0x36a700000 – 0x36a7fffff
- 0x460e00000 – 0x460efffff
- 0x4ea000000 – 0x4ea0fffff
这可以应用GRUB的地址/掩码语法来指定,/etc/default/grub如下所示:
GRUB_BADRAM="0x36a700000,0xfffffffffff00000,0x460e00000,0xfffffffffff00000,0x4ea000000,0xfffffffffff00000"
不消说,node_exporter照样崩溃了,但我知道了这不并是真正的问题地点。
Gentoo Linux在默认的设备文件中启用了-fstack-check。这是为了规避 Stack Clash 马脚。-fstack-check是GCC的一个很老的功能,它有一个副感化,会激发一些异常愚蠢的行动,每个非叶子函数(也就是一个函数调用的函数)只会探测栈指针前4KB的空间。换句话说,用-fstack-check编译的代码可能至少须要4 KB的┞坊空间,除非它是一个叶子函数。
不过,还有一件工作是我可以做的。因为情况会跟着温度的升高而变差,那么如不雅我加热RAM会产生什么呢?
深度发掘
这种缺点很常人,它显然是因为代码运行的某块内存被破坏而引起的。这种缺点很难调试,因为我们无法猜测什么会被破坏(或产生变更),并且我们也无法在产生缺点的时刻捕获到缺点的代码。
推荐阅读
NVIDIA Titan V显卡拆解:211亿晶体管堆出巨型怪物
NVIDIA近日忽然宣布了第一款基于下代12nm Volta架构核心的显卡Titan V(此前的Tesla V100是计算卡),轻轻松松成为地球上最强大年夜的显卡。Titan V基于最高规格的GV100核心,集成211亿个晶>>>详细阅读
本文标题:Go运行时,对bug的分析调试过程解析
地址:http://www.17bianji.com/lsqh/39892.html
1/2 1