具事故具体过程与分析见 http://readfrog.ltd/index.php/archives/58/
写不动了,先放个大概在这里
GoGC回收缓慢

1)GC 只能回收“已经死掉”的对象
如果 Xray 里还有活跃对象,比如:

连接状态
缓冲区
goroutine
session / mux / tls cache
某些 map / queue / stats
那 GC 再勤快也没法收。

所以第一层问题是:

这些内存到底是不是垃圾?

如果不是垃圾,GC 完全无能为力。

2)即使对象是垃圾,GC 回收后 RSS 也未必立刻掉
这是 Go 很容易让人误判的地方。

对象回收后,内存可能只是从:

HeapAlloc
变成
HeapIdle
但仍然保留在 Go 进程手里。

所以你从系统角度看,还是觉得:

这个进程很肥
宿主机可用内存还是少
thrashing 还在
于是你会觉得“GC 没干活”,其实它可能干了,只是没及时把 RSS 还给 OS。

3)在 thrashing 里,GC 自己也会推进困难
你这次最麻烦的就在这里。

GC 不是神仙,它也要:

跑代码
扫堆
访问内存页
被调度到 CPU
而 thrashing 状态下正好:

page cache 被疯狂回收
代码页反复缺页
磁盘读打爆
进程调度被拖慢
所以 GC 本身也会“救火救到自己都快烧着”。

这不是 Go 独有,但 Go 这种长寿服务特别容易撞上。