大部分系统都存在守护进程,进行整个程序的监控
Go中也存在类似的监控G
- 永不终止的循环
- 轮询网络
- 抢占长期占用M的G
- GC
监控
在GMP那一章我们提到过在程序一开始的时候,Go会启动一个主G
等待资源与等待锁并不是同一回事
- 然后由它来创建新的M
- 会根据所在的系统clone出新的线程
- 由该线程调用sysmon启动系统监控
sysmon线程就是Go中进行系统监控的线程
- 先会检查是否存在死锁
- 计算当前线程数
- 通过程序线程相关的数据计算获取
- 0,有活跃线程,无死锁
- <0,程序状态不一致导致的计算不准确
- =0,进一步检查状态
- 有G可以运行(或者正在运行),但是实际上没有线程在跑,说明都在空转,死锁
- 存在休眠状态中的G,且存在等待的计时器(IO资源),否则报错且退出
- 全部G都处于不会再运行的状态时,说明主程序准备退出了
- 是否存在running状态的G
- 处理器上是否存在计时器
- 进入监控循环
- 每次循环都会调用usleep挂起线程
- 运行计时器,获取下一个需要触发的计时器
- 即计算下一次sysmon线程被唤醒的时间
- 轮询网络,处理过期文件描述符
- 非阻塞调用netpoll,获取发生变动的文件描述符,并且把对应的G放入全局队列
- 如果有空闲的M,调用startm启动线程执行
- 抢占运行时间过久的G
- 调用runtime.retake
- 遍历全局的P
- 当前P状态为运行中或者系统调用,且运行时间超过10ms,抢占P
- 在系统调用中的P,如果有其他的G处于队列,抢占P
- GC
- 调用gcTrigger.test判断是否要触发回收
- 需要的话GC使用的G同样需要进入队列