第一课Go程序怎么跑起来的

2021-11-23
1分钟阅读时长

怎么学习? 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的⽣产端

https://www.figma.com/proto/gByIPDf4nRr6No4dNYjn3e/bootstrap?page-id=242%3A7&nodeid=242%3A215&viewport=516%2C209%2C0.07501539587974548&scaling=scale-down-width

goroutine的消费端

https://www.figma.com/proto/gByIPDf4nRr6No4dNYjn3e/bootstrap?page-id=143%3A212&nodeid=143%3A213&viewport=134%2C83%2C0.06213996931910515&scaling=scale-down-width

  • 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

参考

自动编译