第一课Go程序怎么跑起来的
怎么学习? https://xargin.com/how-to-learn
找程序入口
- gdb info files
- readelf -h
- cutter[可视化工具]
- dlv
理解可执⾏⽂件
本节课涉及的⼯具都准备在Dockerfile⾥了,⼤家可以⾃⾏实验
2200000000
FROM centos
RUN yum install golang -y \
&& yum install dlv -y \
&& yum install binutils -y \
&& yum install vim -y \
&& yum install gdb -y
编译方法
# 编译方法
docker build -t test .
docker run -it --rm test bash
Linux的可执⾏⽂件ELF(Executable and Linkable Format)为例,ELF由⼏部分构成:
- ELF header
- Section header
- Sections
参考连接 https://github.com/corkaami/pics
Go进程的启动与初始化
游戏:人力资源机器
环境变量:GOMAXPROCS
调度组件与调度循环
goroutine的⽣产端
goroutine的消费端
G:goroutine,⼀个计算任务。由需要执⾏的代码和其上下⽂组成,上下⽂包括:当前代码位置,栈顶、栈底地址,状态等。
M:machine,系统线程,执⾏实体,想要在CPU上执⾏代码,必须有线程,与C语⾔中的线程相同,通过系统调⽤clone来创建。
P:processor,虚拟处理器,M必须获得P才能执⾏代码,否则必须陷⼊休眠(后台监控线程除外),你也可以将其理解为⼀种token,有这个token,才有在物理CPU核⼼上执⾏的权⼒。
知识点总结
可执⾏⽂件ELF
- 使用go build -x 观察编译连接过程
- 通过readelf -H中的entry找到程序⼊⼝
- 在dlv调试器中b *entry_addr找到代码位置
启动流程
- 处理参数->初始化内部数据结构->主线程->启动调度循环
Runtime构成
- Scheduler、Netpoll、内存管理、垃圾回收
GMP
- M,任务消费者;G,计算任务;P,可以使⽤CPU的token
队列
- P的本地runnext字段-> P的local run queue -> global run queue,多级队列减少锁竞争
调度循环:
- 线程M在持有P的情况下不断消费运⾏队列中的G的过程。
处理阻塞:
可以接管的阻塞:channel收发,加锁,⽹络连接读/写,select
不可接管的阻塞:syscall,cgo,⻓时间运⾏需要剥离P执⾏
sysmon
⼀个后台⾼优先级循环,执⾏时不需要绑定任何的P
负责:
- 检查是否已经没有活动线程,如果是,则崩溃
- 轮询netpoll
- 剥离在syscall上阻塞的M的P
- 发信号,抢占已经执⾏时间过⻓的G
plan9
- https://segmentfault.com/a/1190000039978109
- https://mzh.io/
- https://xargin.com/go-and-plan9-asm/
- http://www.macwk.com/soft/typora
参考
- golang设计
- https://github.com/golang-design
- https://github.com/golang-design/under-the-hood
- https://golang.design/history/
- https://github.com/golang-design/history#scheduler
- https://github.com/gopl-zh/gopl-zh.github.com
- https://github.com/golang-china/gopl-zh
自动编译
- https://facebook.github.io/watchman/
- https://github.com/cosmtrek/air
- https://www.bookstack.cn/read/goframe-1.16-zh/ca68591c9146f8b2.md