前言
gdbgo 1.16.4
gdb调试
gdbgdb
流程调试


如上图,是go程序初始化流程的整理,由于整个流程调用方法非常多,这里挑选较为核心部分进行梳理和分析,这里仅梳理初始化过程的调用流程和次序,用来熟悉初始化的工作机制,不涉及原理性分析,结合这张图的执行次序来说明,如下:

阶段次序语言环境执行文件执行函数核心逻辑
11.1汇编(.s)$GOROOT/src/runtime/rt0_darwin_amd64.s_rt0_amd64_darwin汇编引导
11.2汇编(.s)$GOROOT/src/runtime/asm_amd64.s_rt0_amd64汇编引导
11.3汇编(.s)$GOROOT/src/runtime/asm_amd64.srt0_go汇编引导
22.1golang(.go)$GOROOT/src/runtime/runtime1.goargs整理命令行参数
22.2golang(.go)$GOROOT/src/runtime/os_darwin.goosinit确定CPU数量
22.3golang(.go)$GOROOT/src/runtime/proc.goschedinit初始化、参数、环境处理
22.4golang(.go)$GOROOT/src/runtime/proc.gonewproc创建主goroutine即runtime.main对应的g
22.5golang(.go)$GOROOT/src/runtime/proc.gomstart启动调度循环
22.6golang(.go)$GOROOT/src/runtime/proc.gomain调用main goroutine运行,但不是用户函数入口的main.main
32.3 => 2.3.1golang(.go)$GOROOT/src/runtime/proc.golockInit(xxx)各类Lock的初始化
32.3 => 2.3.2golang(.go)$GOROOT/src/runtime/proc.gosched.maxmcount = 10000最大线程数
32.3 => 2.3.3golang(.go)$GOROOT/src/runtime/proc.gostackinit()栈初始化
32.3 => 2.3.4golang(.go)$GOROOT/src/runtime/proc.gomallocinit()内存管理器初始化
32.3 => 2.3.5golang(.go)$GOROOT/src/runtime/proc.gomcommoninit()调度器初始化
32.3 => 2.3.6golang(.go)$GOROOT/src/runtime/proc.gogoargs()命令行参数处理
32.3 => 2.3.7golang(.go)$GOROOT/src/runtime/proc.gogoenvs()环境变量处理
32.3 => 2.3.8golang(.go)$GOROOT/src/runtime/proc.goparsedebugvars()调试相关参数处理
32.3 => 2.3.9golang(.go)$GOROOT/src/runtime/proc.gogcinit()垃圾回收器初始化
32.6 => 2.6.1golang(.go)$GOROOT/src/runtime/proc.go(64bit-1G 32bit-250M)Stack栈的最大限制
32.6 => 2.6.2golang(.go)$GOROOT/src/runtime/proc.gosystemstack()启动系统后台监控(垃圾回收,并发调度相关)
32.6 => 2.6.3golang(.go)$GOROOT/src/runtime/proc.goruntime_initruntime包内所有init函数初始化
32.6 => 2.6.4golang(.go)$GOROOT/src/runtime/proc.gogcenable()启动垃圾回收
32.6 => 2.6.5golang(.go)$GOROOT/src/runtime/proc.gomain_init用户包内所有init函数初始化
32.6 => 2.6.6golang(.go)$GOROOT/src/runtime/proc.gomain_main调用用户程序入口执行,由编译器动态生成
32.6 => 2.6.7golang(.go)$GOROOT/src/runtime/proc.goexit(0)执行结束
案例分析
mainimportmain_main

项目目录及文件结构,大致如下:

% tree
.
├── funcs
│   └── func.go
├── main.go
funcs/func.go
package funcs

import "fmt"

func init(){
	fmt.Println(" funcs init")
}

func Add(a int, b int) int  {
	fmt.Println("Add method called.")
	return a + b
}
main.go
package main

import (
	//这里导入项目包
	"program/funcs"
	"fmt"
	//这里导入外部包
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func init()  {
	fmt.Println("main init",funcs.Add(4,5))
}

func main() {
	a, b := 1, 2
	fmt.Println("result => ", funcs.Add(a, b))
}
go tool objdump -s “\.init\.0\b” [program]
//===== 系统内部初始化开始 =====
TEXT internal/bytealg.init.0(SB) /usr/local/go/src/internal/bytealg/index_amd64.go
//省略...                           

TEXT runtime.init.0(SB) /usr/local/go/src/runtime/cpuflags_amd64.go
//省略...                                                           

TEXT os.init.0(SB) /usr/local/go/src/os/proc.go
//省略...                           
  proc.go:18            0x10eb852               eb8c                    JMP os.init.0(SB)                       
//省略...                              

//===== 项目包内初始化开始 =====

TEXT program/funcs.init.0(SB) /Users/guanjian/workspace/go/program/funcs/func.go
//省略...                   
  func.go:6             0x10facda               e8617fffff              CALL fmt.Println(SB)                    
//省略...     
  func.go:5             0x10facee               e96dffffff              JMP program/funcs.init.0(SB) 
//省略...                                                               

//===== 外部包初始化开始 =====
TEXT github.com/go-sql-driver/mysql.init.0(SB) /Users/guanjian/go/pkg/mod/github.com/go-sql-driver/mysql@v1.5.0/driver.go
//省略...                                                               
  driver.go:83          0x12707e7               eb97                    JMP github.com/go-sql-driver/mysql.init.0(SB)                                                   
//省略...                                                                                        

TEXT main.init.0(SB) /Users/guanjian/workspace/go/program/main.go
 //省略...                    
  main.go:10            0x128cec0               e83bdee6ff              CALL program/funcs.Add(SB)   
 //省略...                   
  main.go:10            0x128cf75               e8c65ce6ff              CALL fmt.Println(SB)                    
//省略...         
  main.go:9             0x128cf96               e9e5feffff              JMP main.init.0(SB)                     
//省略...                    
//省略...  

下面是将以上编译文件主要信息进行了整理,梳理了初始化顺序、包依赖关系、编译文件映射

初始化顺序

main.main

包依赖关系

initmain.main

编译文件映射

总结
initgoroutinedoInitinitmain.mainimportinitinitinit
参考

《Go语言学习笔记》 雨痕
搭建gdb调试go程序
golang底层 引导、初始化