func main() {
fmt.Printf("Hello World")
}这是我接触go的第一个程序, GMP是我接触go学的最新的东西, 这两者是怎么联系在一起的, GMP是怎么发挥作用的, 为什么init能先于任何函数运行. 了解一下boot-strap, 在此之前, 你需要有gdb工具: brew install gdb
lets get to work
开始了, 我们先编译这个简单的小程序: go build -o main main.go, 接着拿着编译出来的main, 开始debug. 我们的目的是需要知道这个二进制文件第一件执行的事是什么, 我们使用gdb工具打它, 文件, 接着查看它的详细信息:
$ gdb main
$ info files
我们最关心的内容是红色圈中的EntryPoint, 这是什么, 如果你看过dockerfile你会知道, 这种东西象征了第一个需要执行的指令, 来看看第一个需要执行的指令是什么, 是你写的main()吗, 通过info symbol查看这个EntryPoint对应的地址是什么

_rt0_amd64_darwin , 这是什么, 打开runtime里面有一大堆.s结尾的汇编文件:
前往_rt0_amd64_darwin.s中的
_rt0_amd64_darwin(SB)函数这个函数让我们去一个叫做
_rt0_amd64的函数, 这个函数在asm_amd64.s下关于这两个函数是什么, 注释中说 在startup的情况下,我们就会首先执行
_rt0_amd64(SB)函数, 也就是说你的程序上来毛都不干也会先做这个这个函数又将我们指引到
runtime·rt0_go. ok我们的目的达成了, 这里就是bootstrap, 这里面包含了一些MOVQ LEAQ命令跳过, 一些关于CPU的设置跳过, 我们看看在这些预设完成以后, runtime要做什么
初始化
// 初始化
CALL runtime·args(SB)
CALL runtime·osinit(SB)
CALL runtime·schedinit(SB)
// 创建一个G放入待运行队列CALL
runtime·newproc(SB)
// 让主线程进入调度模式
CALL runtime·mstart(SB) 初始化:
stackinit / mallocinit : 内存栈初始化
mcommoninit: 初始化一个m
goargs / goenv : 命令行参数以及环境变量初始化
gcinit : GC初始化
procresize: 根据我们指定的
GOMAXPROCS数量扩容(初始化)全局可用P列表: allp, 并将allp中的p设置成pidle状态
创建G:
将主线程设置成一个G: 通过指定一个需要运行的函数, newproc将创建一个G,用于运行这个函数, 在这里这个函数是指: runtime.main函数, 并不是你写的main函数
这个函数有一个注释: "The main goroutine", 代表这是主函数线程
调度模式开始:
M开始运行, 我们在初始化中创建的M, 在这里会开始运行, 从队列中拿出G也就是main goroutine, 开始运行, 前往runtime.main
启用监控线程sysmon
执行runtime.init函数
启用GC
执行标准库, 第三方库中的init函数
执行用户的init函数