启动过程
环境: go1.8
流程图概览
步骤解释
- 入口文件 runtime/asm_amd64.s
- 根据不同的机器对应不同的文件,本文以mac电脑为例
- 启动入口函数 - _rt0_amd64
- 这是大部分在使用的64位操作系统的通用启动代码,
- JMP runtime·rt0_go(SB) 跳到该函数
- 复制入口参数进入栈中
- 设置tls线程本地存储
- 启动G0/启动M0建立关联关系
- runtime.check - 运行时检查
- args(argc/argv)参数处理
- 调用runtime.args处理
- 调用runtime.osinit
- 获取CPU数量
- 获取物理内存页的大小PageSize,为了将来mallocinit使用
- 调用runtime.schedinit 调度器初始化 - 该处应为启动的核心逻辑(进行各种运行时组件初始化工作,这包括我们的调度器与内存分配器、回收器的初始化)
// The bootstrap sequence is: // // call osinit // call schedinit // make & queue new G // call runtime·mstart // // The new G calls runtime·main. func schedinit() { lockInit(&sched.lock, lockRankSched) lockInit(&sched.sysmonlock, lockRankSysmon) lockInit(&sched.deferlock, lockRankDefer) lockInit(&sched.sudoglock, lockRankSudog) lockInit(&deadlock, lockRankDeadlock) lockInit(&paniclk, lockRankPanic) lockInit(&allglock, lockRankAllg) lockInit(&allpLock, lockRankAllp) lockInit(&reflectOffs.lock, lockRankReflectOffs) lockInit(&finlock, lockRankFin) lockInit(&trace.bufLock, lockRankTraceBuf) lockInit(&trace.stringsLock, lockRankTraceStrings) lockInit(&trace.lock, lockRankTrace) lockInit(&cpuprof.lock, lockRankCpuprof) lockInit(&trace.stackTab.lock, lockRankTraceStackTab) // Enforce that this lock is always a leaf lock. // All of this lock's critical sections should be // extremely short. lockInit(&memstats.heapStats.noPLock, lockRankLeafRank) // raceinit must be the first call to race detector. // In particular, it must be done before mallocinit below calls racemapshadow. _g_ := getg() if raceenabled { _g_.racectx, raceprocctx0 = raceinit() } sched.maxmcount = 10000 // 限制最大系统线程数量 // The world starts stopped. worldStopped() moduledataverify() stackinit() // 栈初始化 mallocinit() // 内存分配器初始化 cpuinit() // must run before alginit alginit() // maps, hash, fastrand must not be used before this call fastrandinit() // must run before mcommoninit mcommoninit(_g_.m, -1) modulesinit() // provides activeModules typelinksinit() // uses maps, activeModules itabsinit() // uses activeModules stkobjinit() // must run before GC starts sigsave(&_g_.m.sigmask) initSigmask = _g_.m.sigmask if offset := unsafe.Offsetof(sched.timeToRun); offset%8 != 0 { println(offset) throw("sched.timeToRun not aligned to 8 bytes") } goargs() goenvs() parsedebugvars() gcinit() // 垃圾回收器初始化 lock(&sched.lock) sched.lastpoll = uint64(nanotime()) // 创建 P // 通过 CPU 核心数和 GOMAXPROCS 环境变量确定 P 的数量 procs := ncpu if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 { procs = n } if procresize(procs) != nil { throw("unknown runnable goroutine during bootstrap") } unlock(&sched.lock) // World is effectively started now, as P's can run. worldStarted() // For cgocheck > 1, we turn on the write barrier at all times // and check all pointer writes. We can't do this until after // procresize because the write barrier needs a P. if debug.cgocheck > 1 { writeBarrier.cgo = true writeBarrier.enabled = true for _, p := range allp { p.wbBuf.reset() } } if buildVersion == "" { // Condition should never trigger. This code just serves // to ensure runtime·buildVersion is kept in the resulting binary. buildVersion = "unknown" } if len(modinfo) == 1 { // Condition should never trigger. This code just serves // to ensure runtime·modinfo is kept in the resulting binary. modinfo = "" } }- newproc 负责根据主 goroutine (即main)入口地址创建可被运行时调度的执行单元
- msstart 开始启动调度器的调度循环