首先,不同于java所有对象分配都在堆上,Golang的对象可能在栈上分配,也可能在堆上分配。所以栈上的对象和堆上的对象可以互相引用。编译时确定对象被分配到堆上还是栈上,这个步骤叫逃逸分析。能被栈帧弹出的对象,一说明在这个对象不会引用函数外别的对象,二说明函数外没别的对象引用它,三说明这个对象不大。
其次,栈的标记比较特殊。Golang的GC是三色标记:从goroutine的栈开始标记,通过栈找到堆顶,最初所有对象为白色,从ROOT开始标灰,再将灰色可达白色标灰,同时扫描过的灰色标黑。
如果严格按照这个规则,每次GC时,需要STW(stop the world)很长时间来全局扫描标记,所以需要并发执行GC。这就会引入以下问题:1. 已经标记为黑色的对象被白色对象引用;2.白色对象被黑色对象引用。这会造成被引用的对象无法标记为黑色,被误回收,所以需要引入内存写屏障(write barrier)策略,管理GC标记时,栈和堆对象并发引用问题。具体可参考混合写屏障提案。