- Go语言的特点
- Go语言的优势
- Go语言的用途
为什么要用Go语言
- C/C++
- C语言不是面向对象
- 直接编译为机器码,不需要执行环境
- 一次编码只能适用一种平台
- 自己处理GC问题(内存泄露)
- Java
- 编译为中间码(字节码)
- 需要特定的执行环境(JVM)
- 一次编译多处执行
- 有虚拟化损失
- JavaScript
- 不需要编译,直接解释执行
- 需要执行环境(浏览器)
- 有虚拟化损失(需要浏览器)
- Go
- 直接编译为二进制,没有虚拟化损失
- 自带运行环境,无需处理GC问题
- 一次编码可以适用多种平台
- 超强的并发支持与并发易用性
![]()
总结
- Go综合了多种语言的优势
- Go是一种天生支持高性能并发的语言
- Go在工业界有广泛的应用
何为Runtime
语言在运行的时候作为支撑的部分 很多语言都有runtime Java-JVM
JavaScript-浏览器内核
Go的Runtime特点
- 没有虚拟机的概念
- Runtime作为程序的一部分打包进二进制产物
- Runtime随用户程序一起运行
- Runtime与用户程序没有明显界限,直接通过函数调用
Go的Runtime能力
- 内存管理能力
- 垃圾回收能力(GC)
- 超强的并发能力(协程调度)
Go的Runtime其他特点
- Runtime有一定的屏蔽system call的能力
- 一些Go的关键字其实是Runtime下的函数
总结
- Go的Runtime负责内存管理、垃圾回收、协程调度
- Go的Runtime被编译为用户程序的一部分、一起运行
关键字 | 函数 |
---|---|
go | newproc |
new | newobject |
make | makeslcie、makechain、makemap… |
<- | chansend,chanrecv1 |
:::success
Go程序是如何编译的?
Example:
:::
package main
import "fmt"
func main() {
fmt.Println("Hello world")
}
:::success
go build -n
输出编译过程
:::
显示结果: #
main
#
mkdir -p $WORK\b001\ cat >$WORK\b001\importcfg << ‘EOF’ # internal
import config //引包
packagefile fmt=D:\Program Files\Go\go1.19\pkg\windowsamd64\fmt.a //编译出来的中间文件 packagefile runtime=D:\Program Files\Go\go1.19\pkg\windows_amd64\runtime.a //中间的机器码文件 EOF cd D:\JetbrainsCode\Learn_Go\GoRedis “D:\Program Files\Go\go1.19\pkg\tool\windows_amd64\compile.exe” -o “$WORK\b001\_pkg.a” -trimpath “$WORK\b001=>” -p main -lang=go1.19 -complet e -buildid yL1vkHRRlkuKDXTvd4Ij/yL1vkHRRlkuKDXTvd4Ij -goversion go1.19 -c=4 -nolocalimports -importcfg “$WORK\b001\importcfg” -pack “D:\JetbrainsCode \LearnGo\GoRedis\main.go” “D:\Program Files\Go\go1.19\pkg\tool\windows_amd64\buildid.exe” -w “$WORK\b001\_pkg.a” # internal cat >$WORK\b001\importcfg.link << ‘EOF’ # internal packagefile main=$WORK\b001_pkg.a packagefile fmt=D:\Program Files\Go\go1.19\pkg\windows_amd64\fmt.a packagefile runtime=D:\Program Files\Go\go1.19\pkg\windows_amd64\runtime.a packagefile errors=D:\Program Files\Go\go1.19\pkg\windows_amd64\errors.a packagefile internal/fmtsort=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\fmtsort.a packagefile io=D:\Program Files\Go\go1.19\pkg\windows_amd64\io.a packagefile math=D:\Program Files\Go\go1.19\pkg\windows_amd64\math.a packagefile os=D:\Program Files\Go\go1.19\pkg\windows_amd64\os.a packagefile reflect=D:\Program Files\Go\go1.19\pkg\windows_amd64\reflect.a packagefile strconv=D:\Program Files\Go\go1.19\pkg\windows_amd64\strconv.a packagefile sync=D:\Program Files\Go\go1.19\pkg\windows_amd64\sync.a packagefile unicode/utf8=D:\Program Files\Go\go1.19\pkg\windows_amd64\unicode\utf8.a packagefile internal/abi=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\abi.a packagefile internal/bytealg=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\bytealg.a packagefile internal/cpu=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\cpu.a packagefile internal/goarch=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\goarch.a packagefile internal/goexperiment=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\goexperiment.a packagefile internal/goos=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\goos.a packagefile runtime/internal/atomic=D:\Program Files\Go\go1.19\pkg\windows_amd64\runtime\internal\atomic.a packagefile runtime/internal/math=D:\Program Files\Go\go1.19\pkg\windows_amd64\runtime\internal\math.a packagefile runtime/internal/sys=D:\Program Files\Go\go1.19\pkg\windows_amd64\runtime\internal\sys.a packagefile internal/reflectlite=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\reflectlite.a packagefile sort=D:\Program Files\Go\go1.19\pkg\windows_amd64\sort.a packagefile math/bits=D:\Program Files\Go\go1.19\pkg\windows_amd64\math\bits.a packagefile internal/itoa=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\itoa.a packagefile internal/oserror=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\oserror.a packagefile internal/poll=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\poll.a packagefile internal/syscall/execenv=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\syscall\execenv.a packagefile internal/syscall/windows=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\syscall\windows.a packagefile internal/testlog=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\testlog.a packagefile internal/unsafeheader=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\unsafeheader.a packagefile io/fs=D:\Program Files\Go\go1.19\pkg\windows_amd64\io\fs.a packagefile sync/atomic=D:\Program Files\Go\go1.19\pkg\windows_amd64\sync\atomic.a packagefile syscall=D:\Program Files\Go\go1.19\pkg\windows_amd64\syscall.a packagefile time=D:\Program Files\Go\go1.19\pkg\windows_amd64\time.a packagefile unicode/utf16=D:\Program Files\Go\go1.19\pkg\windows_amd64\unicode\utf16.a packagefile unicode=D:\Program Files\Go\go1.19\pkg\windows_amd64\unicode.a packagefile internal/race=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\race.a packagefile internal/syscall/windows/sysdll=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\syscall\windows\sysdll.a packagefile path=D:\Program Files\Go\go1.19\pkg\windows_amd64\path.a packagefile internal/syscall/windows/registry=D:\Program Files\Go\go1.19\pkg\windows_amd64\internal\syscall\windows\registry.a modinfo “0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tmain\nmod\tmain\t(devel)\t\nbuild\t-compiler=gc\nbuild\tCGO_ENABLED=1\nbuild\tCGO_CFLAGS=\n build\tCGO_CPPFLAGS=\nbuild\tCGO_CXXFLAGS=\nbuild\tCGO_LDFLAGS=\nbuild\tGOARCH=amd64\nbuild\tGOOS=windows\nbuild\tGOAMD64=v1\nbuild\tvcs=git\nbuild\tvcs .revision=55e510c654b410d49fee106291d645a06d084643\nbuild\tvcs.time=2022-09-21T06:23:56Z\nbuild\tvcs.modified=true\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\ xd8\xf2” EOF mkdir -p $WORK\b001\exe\ cd . “D:\Program Files\Go\go1.19\pkg\tool\windows_amd64\link.exe” -o //链接这些
.a
文件成.exe文件
“$WORK\b001\exe\a.out.exe” -importcfg “$WORK\b001\importcfg.link” -buildmode =pie -buildid=2naWCJTmkVUCrFKumC0d/yL1vkHRRlkuKDXTvd4Ij/yL1vkHRRlkuKDXTvd4Ij/2naWCJTmkVUCrFKumC0d -extld=gcc “$WORK\b001\_pkg.a” “D:\Program Files\Go\go1.19\pkg\tool\windows_amd64\buildid.exe” -w “$WORK\b001\exe\a.out.exe” # internal mv $WORK\b001\exe\a.out.exe main.exe
- 词法分析、句法分析、语义分析归属于编译
词法分析
- 将源代码翻译成
Token
Token
是代码中的最小语义结构句法分析
- Token序列经过处理,变成语法树
- SST(抽象语法树)
:::info 语义分析
- 类型检查
- 类型推断
- 查看类型是否匹配
- 函数调用内联
逃逸分析
- Go的变量是放在堆上还是放在栈上 ::: :::success 中间码生成(SSA)
为了处理不同平台的差异,先生成中间代码(SSA 平台无关汇编)
代码优化
- 每一个过程当中都有代码优化的过程
:::
:::tips
查看从代码到SSA中间码的整个过程
Windows:$env:GOSSAFUNC="main"
Linux:export GOSSAFUNC="main"
:::go build
:::tips
runtime
dumped SSA to D:\JetbrainsCode\Learn_Go\GoRedis\ssa.html
# main
dumped SSA to .\ssa.html
::: ssa.html
截图示意
最后一步,生成SSA 研究和排查Go语言的时候有用
# D:\JetbrainsCode\Learn_Go\GoRedis\main.go
00000 (5) TEXT main.main(SB), ABIInternal
00001 (5) FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
00002 (5) FUNCDATA $1, gclocals·EaPwxsZ75yY1hHMVZLmk6g==(SB)
00003 (5) FUNCDATA $2, main.main.stkobj(SB)
v35
00004 (+6) MOVUPS X15, main..autotmp_8-16(SP)
v14
00005 (6) LEAQ type.string(SB), DX
v5
00006 (6) MOVQ DX, main..autotmp_8-16(SP)
v20
00007 (6) LEAQ main..stmp_0(SB), DX
v36
00008 (6) MOVQ DX, main..autotmp_8-8(SP)
v27
00009 (?) NOP
# $GOROOT\src\fmt\print.go
v30
00010 (+294) MOVQ os.Stdout(SB), BX
v22
00011 (294) LEAQ go.itab.*os.File,io.Writer(SB), AX
v13
00012 (294) LEAQ main..autotmp_8-16(SP), CX
v16
00013 (294) MOVL $1, DI
v7
00014 (294) MOVQ DI, SI
v32
00015 (294) PCDATA $1, $0
v32
00016 (294) CALL fmt.Fprintln(SB)
# D:\JetbrainsCode\Learn_Go\GoRedis\main.go
b4
00017 (7) RET
00018 (?) END
机器码生成
- 先生成Plan9汇编代码
- 最后编译为机器码
- 输出的机器码为
.a
文件- 查看Plan9汇编代码
go build -gcflags -S main.go
# runtime
dumped SSA to D:\JetbrainsCode\Learn_Go\GoRedis\ssa.html
# command-line-arguments
dumped SSA to .\ssa.html
main.main STEXT size=103 args=0x0 locals=0x40 funcid=0x0 align=0x0
0x0000 00000 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) TEXT main.main(SB), ABIInternal, $64-0
0x0000 00000 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) CMPQ SP, 16(R14)
0x0004 00004 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) PCDATA $0, $-2
0x0004 00004 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) JLS 92
0x0006 00006 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) PCDATA $0, $-1
0x0006 00006 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) SUBQ $64, SP
0x000a 00010 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) MOVQ BP, 56(SP)
0x000f 00015 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) LEAQ 56(SP), BP
0x0014 00020 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
0x0014 00020 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) FUNCDATA $1, gclocals·EaPwxsZ75yY1hHMVZLmk6g==(SB)
0x0014 00020 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) FUNCDATA $2, main.main.stkobj(SB)
0x0014 00020 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:6) MOVUPS X15, main..autotmp_8+40(SP)
0x001a 00026 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:6) LEAQ type.string(SB), DX
0x0021 00033 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:6) MOVQ DX, main..autotmp_8+40(SP)
0x0026 00038 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:6) LEAQ main..stmp_0(SB), DX
0x002d 00045 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:6) MOVQ DX, main..autotmp_8+48(SP)
0x0032 00050 (<unknown line number>) NOP
0x0032 00050 ($GOROOT\src\fmt\print.go:294) MOVQ os.Stdout(SB), BX
0x0039 00057 ($GOROOT\src\fmt\print.go:294) LEAQ go.itab.*os.File,io.Writer(SB), AX
0x0040 00064 ($GOROOT\src\fmt\print.go:294) LEAQ main..autotmp_8+40(SP), CX
0x0045 00069 ($GOROOT\src\fmt\print.go:294) MOVL $1, DI
0x004a 00074 ($GOROOT\src\fmt\print.go:294) MOVQ DI, SI
0x004d 00077 ($GOROOT\src\fmt\print.go:294) PCDATA $1, $0
0x004d 00077 ($GOROOT\src\fmt\print.go:294) CALL fmt.Fprintln(SB)
0x0052 00082 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:7) MOVQ 56(SP), BP
0x0057 00087 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:7) ADDQ $64, SP
0x005b 00091 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:7) RET
0x005c 00092 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:7) NOP
0x005c 00092 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) PCDATA $1, $-1
0x005c 00092 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) PCDATA $0, $-2
0x005c 00092 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) NOP
0x0060 00096 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) CALL runtime.morestack_noctxt(SB)
0x0065 00101 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) PCDATA $0, $-1
0x0065 00101 (D:\JetbrainsCode\Learn_Go\GoRedis\main.go:5) JMP 0
0x0000 49 3b 66 10 76 56 48 83 ec 40 48 89 6c 24 38 48 I;f.vVH..@H.l$8H
0x0010 8d 6c 24 38 44 0f 11 7c 24 28 48 8d 15 00 00 00 .l$8D..|$(H.....
0x0020 00 48 89 54 24 28 48 8d 15 00 00 00 00 48 89 54 .H.T$(H......H.T
0x0030 24 30 48 8b 1d 00 00 00 00 48 8d 05 00 00 00 00 $0H......H......
0x0040 48 8d 4c 24 28 bf 01 00 00 00 48 89 fe e8 00 00 H.L$(.....H.....
0x0050 00 00 48 8b 6c 24 38 48 83 c4 40 c3 0f 1f 40 00 ..H.l$8H..@...@.
0x0060 e8 00 00 00 00 eb 99 .......
rel 2+0 t=23 type.string+0
rel 2+0 t=23 type.*os.File+0
rel 29+4 t=14 type.string+0
rel 41+4 t=14 main..stmp_0+0
rel 53+4 t=14 os.Stdout+0
rel 60+4 t=14 go.itab.*os.File,io.Writer+0
rel 78+4 t=7 fmt.Fprintln+0
rel 97+4 t=7 runtime.morestack_noctxt+0
go.cuinfo.producer.main SDWARFCUINFO dupok size=0
0x0000 72 65 67 61 62 69 regabi
go.cuinfo.packagename.main SDWARFCUINFO dupok size=0
0x0000 6d 61 69 6e main
go.info.fmt.Println$abstract SDWARFABSFCN dupok size=42
0x0000 05 66 6d 74 2e 50 72 69 6e 74 6c 6e 00 01 01 13 .fmt.Println....
0x0010 61 00 00 00 00 00 00 13 6e 00 01 00 00 00 00 13 a.......n.......
0x0020 65 72 72 00 01 00 00 00 00 00 err.......
rel 0+0 t=22 type.[]interface {}+0
rel 0+0 t=22 type.error+0
rel 0+0 t=22 type.int+0
rel 19+4 t=31 go.info.[]interface {}+0
rel 27+4 t=31 go.info.int+0
rel 37+4 t=31 go.info.error+0
main..inittask SNOPTRDATA size=32
0x0000 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
0x0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
rel 24+8 t=1 fmt..inittask+0
go.string."Hello world" SRODATA dupok size=11
0x0000 48 65 6c 6c 6f 20 77 6f 72 6c 64 Hello world
go.itab.*os.File,io.Writer SRODATA dupok size=32
0x0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0010 5a 22 ee 60 00 00 00 00 00 00 00 00 00 00 00 00 Z".`............
rel 0+8 t=1 type.io.Writer+0
rel 8+8 t=1 type.*os.File+0
rel 24+8 t=-32767 os.(*File).Write+0
main..stmp_0 SRODATA static size=16
0x0000 00 00 00 00 00 00 00 00 0b 00 00 00 00 00 00 00 ................
rel 0+8 t=1 go.string."Hello world"+0
runtime.nilinterequal·f SRODATA dupok size=8
0x0000 00 00 00 00 00 00 00 00 ........
rel 0+8 t=1 runtime.nilinterequal+0
runtime.memequal64·f SRODATA dupok size=8
0x0000 00 00 00 00 00 00 00 00 ........
rel 0+8 t=1 runtime.memequal64+0
runtime.gcbits.01 SRODATA dupok size=1
0x0000 01 .
type..namedata.*interface {}- SRODATA dupok size=15
0x0000 00 0d 2a 69 6e 74 65 72 66 61 63 65 20 7b 7d ..*interface {}
type.*interface {} SRODATA dupok size=56
0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 3b fc f8 8f 08 08 08 36 00 00 00 00 00 00 00 00 ;......6........
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.memequal64·f+0
rel 32+8 t=1 runtime.gcbits.01+0
rel 40+4 t=5 type..namedata.*interface {}-+0
rel 48+8 t=1 type.interface {}+0
runtime.gcbits.02 SRODATA dupok size=1
0x0000 02 .
type.interface {} SRODATA dupok size=80
0x0000 10 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 ................
0x0010 39 7a 09 0f 02 08 08 14 00 00 00 00 00 00 00 00 9z..............
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
rel 24+8 t=1 runtime.nilinterequal·f+0
rel 32+8 t=1 runtime.gcbits.02+0
rel 40+4 t=5 type..namedata.*interface {}-+0
rel 44+4 t=-32763 type.*interface {}+0
rel 56+8 t=1 type.interface {}+80
type..namedata.*[]interface {}- SRODATA dupok size=17
0x0000 00 0f 2a 5b 5d 69 6e 74 65 72 66 61 63 65 20 7b ..*[]interface {
0x0010 7d }
type.*[]interface {} SRODATA dupok size=56
0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 9d 9c 0e 59 08 08 08 36 00 00 00 00 00 00 00 00 ...Y...6........
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.memequal64·f+0
rel 32+8 t=1 runtime.gcbits.01+0
rel 40+4 t=5 type..namedata.*[]interface {}-+0
rel 48+8 t=1 type.[]interface {}+0
type.[]interface {} SRODATA dupok size=56
0x0000 18 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 76 de 99 0d 02 08 08 17 00 00 00 00 00 00 00 00 v...............
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 32+8 t=1 runtime.gcbits.01+0
rel 40+4 t=5 type..namedata.*[]interface {}-+0
rel 44+4 t=-32763 type.*[]interface {}+0
rel 48+8 t=1 type.interface {}+0
type..namedata.*[1]interface {}- SRODATA dupok size=18
0x0000 00 10 2a 5b 31 5d 69 6e 74 65 72 66 61 63 65 20 ..*[1]interface
0x0010 7b 7d {}
type.*[1]interface {} SRODATA dupok size=56
0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 a8 0e 57 36 08 08 08 36 00 00 00 00 00 00 00 00 ..W6...6........
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.memequal64·f+0
rel 32+8 t=1 runtime.gcbits.01+0
rel 40+4 t=5 type..namedata.*[1]interface {}-+0
rel 48+8 t=1 type.[1]interface {}+0
type.[1]interface {} SRODATA dupok size=72
0x0000 10 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 ................
0x0000 00 03 66 6d 74 ..fmt
gclocals·g2BeySu+wFnoycgXfElmcg== SRODATA dupok size=8
0x0000 01 00 00 00 00 00 00 00 ........
gclocals·EaPwxsZ75yY1hHMVZLmk6g== SRODATA dupok size=9
0x0000 01 00 00 00 02 00 00 00 00 .........
main.main.stkobj SRODATA static size=24
0x0000 01 00 00 00 00 00 00 00 f0 ff ff ff 10 00 00 00 ................
0x0010 10 00 00 00 00 00 00 00 ........
rel 20+4 t=5 runtime.gcbits.02+0
Go程序是如何运行的?
Go程序的入口
- main方法?
runtime/rt0_操作系统_芯片架构.s
此处的版本为
go1.19
windows/amd64
$GOROOT\src\runtime\rt0_windows_amd64.s
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go_asm.h"
#include "go_tls.h"
#include "textflag.h"
TEXT _rt0_amd64_windows(SB),NOSPLIT,$-8
JMP _rt0_amd64(SB)
// When building with -buildmode=(c-shared or c-archive), this
// symbol is called. For dynamic libraries it is called when the
// library is loaded. For static libraries it is called when the
// final executable starts, during the C runtime initialization
// phase.
// Leave space for four pointers on the stack as required
// by the Windows amd64 calling convention.
TEXT _rt0_amd64_windows_lib(SB),NOSPLIT,$0x20
// Create a new thread to do the runtime initialization and return.
MOVQ _cgo_sys_thread_create(SB), AX
MOVQ $_rt0_amd64_windows_lib_go(SB), CX
MOVQ $0, DX
CALL AX
RET
TEXT _rt0_amd64_windows_lib_go(SB),NOSPLIT,$0
MOVQ $0, DI
MOVQ $0, SI
MOVQ $runtime·rt0_go(SB), AX
JMP AX
查找
_rt0_amd64
跳转到那个文件runtime/asm_amd64.s
// _rt0_amd64 is common startup code for most amd64 systems when using
// internal linking. This is the entry point for the program from the
// kernel for an ordinary -buildmode=exe program. The stack holds the
// number of arguments and the C-style argv.
TEXT _rt0_amd64(SB),NOSPLIT,$-8
MOVQ 0(SP), DI // argc
LEAQ 8(SP), SI // argv
JMP runtime·rt0_go(SB)
line 6/7 将argc和argc放入到寄存器当中
JMP runtime·rt0_go(SB)
调用runtime·rt0_go
Line 159 ~ 212
TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0
// copy arguments forward on an even stack
// 在均匀的堆栈上向前复制实参(YNMT翻译)
MOVQ DI, AX // argc
MOVQ SI, BX // argv
SUBQ $(5*8), SP // 3args 2auto
ANDQ $~15, SP
MOVQ AX, 24(SP)
MOVQ BX, 32(SP)
// create istack out of the given (operating system) stack.
// _cgo_init may update stackguard.
// 从给定的(操作系统)堆栈中创建istack。
// _cgo_init可能会更新stackguard。
// 初始化一个g0的协程 不归调度器管理
MOVQ $runtime·g0(SB), DI
LEAQ (-64*1024+104)(SP), BX
MOVQ BX, g_stackguard0(DI)
MOVQ BX, g_stackguard1(DI)
MOVQ BX, (g_stack+stack_lo)(DI)
MOVQ SP, (g_stack+stack_hi)(DI)
// find out information about the processor we're on
MOVL $0, AX
CPUID
CMPL AX, $0
JE nocpuinfo
CMPL BX, $0x756E6547 // "Genu"
JNE notintel
CMPL DX, $0x49656E69 // "ineI"
JNE notintel
CMPL CX, $0x6C65746E // "ntel"
JNE notintel
MOVB $1, runtime·isIntel(SB)
notintel:
// Load EAX=1 cpuid flags
MOVL $1, AX
CPUID
MOVL AX, runtime·processorVersionInfo(SB)
nocpuinfo:
// if there is an _cgo_init, call it.
MOVQ _cgo_init(SB), AX
TESTQ AX, AX
JZ needtls
// arg 1: g0, already in DI
MOVQ $setg_gcc<>(SB), SI // arg 2: setg_gcc
#ifdef GOOS_android
MOVQ $runtime·tls_g(SB), DX // arg 3: &tls_g
// arg 4: TLS base, stored in slot 0 (Android's TLS_SLOT_SELF).
// Compensate for tls_g (+16).
MOVQ -16(TLS), CX
#else
MOVQ $0, DX // arg 3, 4: not used when using platform's TLS
MOVQ $0, CX
#endif
读取命令行参数
CALL runtime·check(SB)
> 然后跳转到`runtime/runtime1.go`
<a name="zSVJb"></a>
## 运行时检测
- 检查各种类型的长度
- 检查指针操作
- 检查结构体字段的偏移量
- 检查`atomic`原子操作
- 检查CAS操作
- 检查栈大小是否是2的幂次
Line343~345
CALL runtime·args(SB) //argc argv 拷贝到Go语言当中
CALL runtime·osinit(SB) //osinit判断系统的字长和系统的核数
CALL runtime·schedinit(SB)
<a name="IQwfs"></a>
## 参数初始化runtime.argc
- 对命令行中的参数进行处理
- 参数数量复制给argc int32
- 参数值复制给argv **byte
<a name="mlbGR"></a>
## 调度器初始化 runtime.schedinit
- 全局栈空间内存分配
- 加载命令行参数到`os.Args`
- 堆内存空间的初始化
- 加载操作系统环境变量
- 初始化当前系统线程
- 垃圾回收器的参数初始化
- 算法初始化(map、hash)
- 设置`process`数量
Line348
MOVQ $runtime·mainPC(SB), AX // entry
> mainPC
Line375~379
// mainPC is a function value for runtime.main, to be passed to newproc.
// The reference to runtime.main is made via ABIInternal, since the
// actual function (not the ABI0 wrapper) is needed by newproc.
DATA runtime·mainPC+0(SB)/8,$runtime·main
> runtime.main跳转runtime/proc.go
> 执行main.main
line199 doInit(&runtime_inittask) // Must be before defer. line209 gcenable() //打开垃圾回收器 line233 doInit(&main_inittask)
//go:linkname main_main main.main func main_main()
```
Line353~356
----------------------------------------------
// start this M
CALL runtime·mstart(SB)
CALL runtime·abort(SB) // mstart should never return
Line389~391
----------------------------------------------
TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0
CALL runtime·mstart0(SB)
RET // not reached
创建主协程
- 创建一个新的协程,执行runtime.main
-
初始化M
-
主协程执行主函数
执行runtime包中的init方法
- 启动GC垃圾收集器
- 执行用户包依赖的init方法
-
总结
Go启动时经历了检查、各种初始化、初始化协程调度的过程
-
问题
调度器是什么?
- 为什么初始化M
为什么不是直接执行main.main(),而是将其放入调度器?
体会
-
Go语言是面向对象的吗?
:::info Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy. The concept of “interface” in Go provides a different approach that we believe is easy to use and in some ways more general. There are also ways to embed types in other types to provide something analogous—but not identical—to subclassing. Moreover, methods in Go are more general than in C++ or Java: they can be defined for any sort of data, even built-in types such as plain, “unboxed” integers. They are not restricted to structs (classes).
Also, the lack of a type hierarchy makes “objects” in Go feel much more lightweight than in languages such as C++ or Java. :::
是又不是。尽管 Go 有类型和方法并允许面向对象的编程风格,但没有类型层次结构。Go 中的“接口”概念提供了一种不同的方法,我们认为这种方法易于使用,并且在某些方面更通用。还有一些方法可以将类型嵌入到其他类型中,以提供与子类化类似但不完全相同的东西。此外,Go 中的方法比 C++ 或 Java 中的方法更通用:它们可以为任何类型的数据定义,甚至是内置类型,例如普通的“unboxed”整数。它们不限于结构(类)。 此外,没有类型层次结构使得 Go 中的“对象”感觉比 C++ 或 Java 等语言更轻量。