分段栈: Go1.4之前的栈管理技术,运行时给每个goroutine分配8K的初始化栈内存; 在每个go函数之前有个代码块,检查已分配栈空间已不足, 不足的话会调用morestack函数来分配一段新的内存作栈空间, 然后将包括上一个栈地址等信息的struct和lessmore函数写入栈底, 接着重启gorouine,从将原来栈空间用光的函数开始执行(这里称为stack split)。 等该函数执行返回时,通过lessstack函数查找栈底部struct来调整栈指针, 使得返回原来栈空间,同时将该新栈段释放掉。 连续栈: Go1.4之后使用连续栈,同样在每个函数入口进行栈溢出检查, 只是在栈溢出时会申请一个两倍于当前栈空间的内存空间, 然后把当前旧栈拷贝到新栈,释放旧栈空间, 最后程序重启goroutine并从引起重新分配栈段的函数继续执行。 实现栈拷贝的关键: 1. 只有在栈上分配的指针才能指向栈上的地址; 2. 需要知道栈上哪部分是指针,因为移动栈时需要把所有的指针指向新的目标地址; 原来Go运行时很多是C写的,大量运行时调用没有指针信息可用,这也是Go runtime被大规模重构的主要原因。