【Golang源码分析】golang的启动原理

简介: 【Golang源码分析】golang的启动原理

  随着技术的发展,大多的PHPer都开始转型golang。这个也是golang因为go的一些特别深受大家喜爱。我们团队也在试水,在内部的一些小项目上做了试探。在此同时我作为试探的一员身先士卒,沙场练兵。从中也琢磨到一些技巧希望能和大家一起学习共勉。


一、前期准备:

     go版本:go1.13.4

      由于是做源码分析调试,我们必须找到适合自己的工具。咱们调试的话可以考虑几种工具

       1)gdb    linux使用比较合适

       2)lldb   mac自带,不过建议dlv

       3)dlv    go开发的调试工具


       本文中主要以dlv为主,接下来我们一起来安装一下dlv。  

   第一步下载

#go get -u github.com/derekparker/delve/cmd/dlv

   

第二步编译:

#git clone https://github.com/go-delve/delve.git $GOPATH/src/github.com/go-delve/delve

#cd $GOPATH/src/github.com/go-delve/

#make install

$GOPATH 是golang的环境变量,我使用的是Linux,建议大家在/etc/profile设置,mac相同。

windows设置gopath

https://jingyan.baidu.com/article/5d368d1eb616133f60c057bf.html

   第三步设置环境变量:

#vim /etc/profile

export PATH=$PATH:/data/gopath/bin

/data/gopath/bin 为你自己的go的bin目录

初始化环境变量

#source /etc/profile


dlv参数介绍(常用)


命令(全) 命令(简写) 备注
restart r 重新启动程序
continue c 运行到断点或者程序终止
break b 设置断点
breakpoints bp 打印设置断点
next n 执行下一行
list l 查看当前代码
step s 进入下一层
stack bt 当前调用栈
print p 打印变量


二.调试:

    1.编译调试文件  

   代码内容

package main

import (

   "fmt"

)

 

func main() {

    var p **int    

    var i int = 10    

    var p1 *int = &i    

    fmt.Println("p1=", p1)    

   

    p = &p1    

    fmt.Println("p=", p)

}

   编译

#go build -gcflags=all="-N -l" pointer.go

必须这样编译,待能用dlv打印导出变量信息;


   2.载入文件

#dlv exec ./pointer


设置rt0_go断点,程序入口

(dlv) break runtime.rt0_go

是不是很好奇为什么入口在runtime.rt0_go

可以打开程序后输入r,在输入list,然后在输入si;si是单步cpu指令;

其实go在运行时会根据系统和CPU的不同,找到底层代码下的,rt0_**.s的汇编代码,汇编代码中再去调转到runtime.rt0_go 。

当然由于系统的不同可执行程序的形式不同。

   常见的可执行程序可以分为三大类:

   1)PE文件    

        PE文件主要是Windows系列系统,可执行文件索引;

   2)ELF文件    

       ELF文件是linux系列系统,可执行文件索引;

   3)mach-o文件    

       mach-o是mac系列系统的可执行文件格式,苹果系统是基于FreeBSD的,属于unix-like操作系统;

   有一篇比较不错的文章可以推荐给大家:

   https://blog.csdn.net/abc_12366/article/details/88205670


好的我们继续往下说,我们进入


我们按住n执行停留到212行

我们可以看到runtime.args 、runtime.osinit和runtime.schedinit三个函数调用。我们可以依次输入si进入函数体内查看

(div)si

args函数主要用途整理命令行参数;


osint函数是确定CPU Core数量


schedinit源码如下:

schedinit主要作用是所有运行时环境初始化;我们继续下一个断点,然后往下执行:

(dlv)b runtime.main  

(dlv)n



runtime/proc.go部分源码

func main() {  

 g := getg()        

 g.m.g0.racectx = 0  

 

 // 执行栈最大限制 64位系统1GB,32位系统250MB    

 if sys.PtrSize == 8 {      

     maxstacksize = 1000000000    

 } else {      

     maxstacksize = 250000000

 }    

 

 // 允许newproc启动新Ms。    

 mainStarted = true    

 

 if GOARCH != "wasm" { // wasm上还没有线程,所以没有sysmon      

     // 启动系统后监控(并发任务调度相关)      

     systemstack(func() {          

         newm(sysmon, nil)      

     })    

 }    

 ...      

 //启动垃圾回收器后台操作        

 gcenable()    

 ...        

 //进行间接调用,因为链接器在放置运行时不知道主包的地址。这个就是我们程序文件入口    

 //其实就是用户main.main函数    

 fn := main_main    

 fn()      

 

 //执行结束    

 exit(0)    

}

我们执行到fn()出可以按s

(dlv)s

这样就来到了我们程序的代码;这时我们可以看一下我们的调度栈

执行完成程序完成之后又回到runtime/proc.go中if atomic.Load(&runningPanicDefers) 处

继续往下执行,一直到exit(0)处,按si执行。

程序回到sys_linux_amd64.s汇编代码中的runtime.exit

最终程序结束;


三.调用流程:

非goroutine退出情况


相关文章
|
6月前
|
编译器 Go
Golang底层原理剖析之method
Golang底层原理剖析之method
41 2
|
6月前
|
存储 Go
Golang底层原理剖析之map
Golang底层原理剖析之map
60 1
|
6月前
|
Java Go
Golang底层原理剖析之垃圾回收GC(二)
Golang底层原理剖析之垃圾回收GC(二)
114 0
|
6月前
|
存储 SQL 安全
Golang底层原理剖析之上下文Context
Golang底层原理剖析之上下文Context
143 0
|
6月前
|
存储 编译器 Go
Golang底层原理剖析之闭包
Golang底层原理剖析之闭包
82 0
|
18天前
|
存储 安全 测试技术
GoLang协程Goroutiney原理与GMP模型详解
本文详细介绍了Go语言中的Goroutine及其背后的GMP模型。Goroutine是Go语言中的一种轻量级线程,由Go运行时管理,支持高效的并发编程。文章讲解了Goroutine的创建、调度、上下文切换和栈管理等核心机制,并通过示例代码展示了如何使用Goroutine。GMP模型(Goroutine、Processor、Machine)是Go运行时调度Goroutine的基础,通过合理的调度策略,实现了高并发和高性能的程序执行。
77 29
|
16天前
|
负载均衡 算法 Go
GoLang协程Goroutiney原理与GMP模型详解
【11月更文挑战第4天】Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理,创建和销毁开销小,适合高并发场景。其调度采用非抢占式和协作式多任务处理结合的方式。GMP 模型包括 G(Goroutine)、M(系统线程)和 P(逻辑处理器),通过工作窃取算法实现负载均衡,确保高效利用系统资源。
|
3月前
|
算法 NoSQL 关系型数据库
熔断原理与实现Golang版
熔断原理与实现Golang版
|
3月前
|
存储 关系型数据库 Go
SOLID原理:用Golang的例子来解释
SOLID原理:用Golang的例子来解释
|
3月前
|
存储 人工智能 Go
golang 反射基本原理及用法
golang 反射基本原理及用法
29 0