GDB工具分析golang源码
整体引导顺序:
line 8
根据:asm_amd64.s文件的内容,以下go文件被顺序调用:先call一些初始化,最后调用runtime的main。
在runtime.main() 中:执行栈最大限制,启动垃圾回收,执行runtime包内所有初始化init,启动垃圾回收后台操作,执行所有的用户包,包括标准库,的初始化init,执行用户逻辑入口main.main函数。执行结束,返回退出状态码。
//go:linkname runtime_init runtime.init 表示由编译器动态生成
func runtime_init()
编译器动态生成的方法还有:func main_init()
所有init会在同一个go程执行,所有init结束后才会执行main
安装gdb和写一个测试函数main.go;编译成test;gdb test调试test文件。
1.汇编针对特定平台的引导
注意源码文件中的中间的.,要写成最下的.
2.初始化
至此 汇编平台针对go平台的引导过程完成。
整个初始化过程比较繁琐,要完成诸如命令行参数整理,环境变量设置,内存分配器,垃圾回收器,和并发调度的现场准备。
- 根据如下过程,初始化的runtime:
b runtime.args 整理命令行参数
Breakpoint 6 at 0x436230: file /home/yz/go/goroot/go/src/runtime/runtime1.go, line 60.
b runtime.osinit 确定cpucore数量
Breakpoint 7 at 0x4264e0: file /home/yz/go/goroot/go/src/runtime/os_linux.go, line 277.
b runtime.schedinit 我们关注的所有运行时环境初始化构造都在这里呗调用
Breakpoint 8 at 0x42a8f0: file /home/yz/go/goroot/go/src/runtime/proc.go, line 526.
最大系统线程数限制为:10000
goargs() goenvs()处理命令行参数和环境变量
gcinit()垃圾回收器初始化
procs := ncpu//通过cpu core 和gomaxprocs环境变量确定p数量,默认是cpu个数
if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 {
procs = n
}
if procresize(procs) != nil {
throw("unknown runnable goroutine during bootstrap")
}
内存分配器、垃圾回收器,并发调度器的初始化细节需要很多专属特征,先不去理会。
- 进入 runtime.main
runtime/proc.go line110
3.内存分配
所有内置运行时的编程语言通常会抛弃传统的内存分配方式,该自主管理。这样可以完成类似预分配,内存池等操作。以避开系统调用带来的性能问题,而且,可以更好滴配合垃圾回收。
go的内存分配策略:
1.每次从os申请一大块内存如1MB,以减少系统调用;2.把申请导的大块内存按照特定大小预先分成小块,构成链表。
3.为对象分配内存时,从链表提取一个小块;4.回收内存对象时候,把小块重新归还到链表
5.如闲置内存过多,则偿还部分给os.
内存分配至管理内存块,不关心对象状态。且不会主动回收内存,由垃圾回收清理后,触发内存分配回收操作。