GO可以說是近幾年最熱門的新興語言之一了, 一般人看到 分散式 和 大數據 就會想到GO, 這個系列的文章會通過研究golang的源代碼來分析內部的實現原理, 和CoreCLR不同的是, golang的源代碼已經被很多人研究過了, 我將會著重研究他們未提到過的部分. 另一點和CoreCLR不同的是, ...
GO可以說是近幾年最熱門的新興語言之一了, 一般人看到分散式和大數據就會想到GO,
這個系列的文章會通過研究golang的源代碼來分析內部的實現原理,
和CoreCLR不同的是, golang的源代碼已經被很多人研究過了, 我將會著重研究他們未提到過的部分.
另一點和CoreCLR不同的是, golang的源代碼非常易懂, 註釋也非常的豐富,
很明顯Google的工程師在寫代碼的時候有考慮其他人會去看這份代碼.
儘管代碼非常易懂, 研究它們還是需要實際運行和調試才能得到更好的理解,
這個系列分析的golang源代碼是Google官方的實現的1.9.2版本, 不適用於其他版本和gccgo等其他實現,
運行環境是Ubuntu 16.04 LTS 64bit.
編譯golang源代碼
go的源代碼是用go寫的, 編譯也需要一個可運行的go.
首先我們從官網下載源代碼和二進位文件.
go1.9.2.src.tar.gz
go1.9.2.linux-amd64.tar.gz
註意兩個壓縮包解壓出來文件夾名稱都是go, 我們解壓到以下目錄:
源代碼: ~/git_go/go_src
二進位: ~/git_go/go_bin
編譯go之前需要設置環境變數,
GOROOT_BOOTSTRAP
是go二進位文件夾的所在目錄,
GO_GCFLAGS
是編譯go時使用的參數.
export GOROOT_BOOTSTRAP=~/git_go/go_bin
export GO_GCFLAGS="-N -l"
這裡的-N
參數代表禁止優化, -l
參數代表禁止內聯, go在編譯目標程式的時候會嵌入運行時(runtime)的二進位,
禁止優化和內聯可以讓運行時(runtime)中的函數變得更容易調試.
都準備好以後就可以進入go的源代碼文件夾執行all.bash
編譯了:
編譯的結果在~/git_go/go_src/bin
下:
調試golang源代碼
之前CoreCLR的系列中我使用了lldb, 在這個系列中我繼續沿用這個調試器.
這個系列中使用的是lldb 4.0.
以以下源代碼(hello.go)為例:
package main
import (
"fmt"
"time"
)
func printNumber(from, to int, c chan int) {
for x := from; x <= to; x++ {
fmt.Printf("%d\n", x)
time.Sleep(1 * time.Millisecond)
}
c <- 0
}
func main() {
c := make(chan int, 3)
go printNumber(1, 3, c)
go printNumber(4, 6, c)
_, _ = <- c, <- c
}
編譯源代碼使用以下命令, 這裡的-l
參數的意思和上面一樣, 如果有需要還可以加-N
參數:
~/git_go/go_src/bin/go build -gcflags "-l" hello.go
編譯後使用lldb運行:
lldb ./hello
go裡面的函數符號名稱的命名規則是包名稱.函數名稱
, 例如主函數的符號名稱是main.main
, 運行時中的newobject
的符號名稱是runtime.newobject
.
首先給主函數下一個斷點然後運行:
可以看到成功的進入了主函數, 並且有源代碼提示.
接下來給按文件名和行數來下斷點:
然後查看函數的彙編代碼:
關於lldb的命令可以查看這篇文檔.
在我使用的環境中lldb可以正常的下斷點, 步進和步過go代碼或者彙編指令,
但列印變數輸出的值有可能是錯的, 即使不開啟優化.
雖然列印變數這個功能不好用, 我們仍然可以直接讓go輸出我們想要的值,
例如修改runtime/malloc.go
輸出當前環境下arena|spans|bitmap區的大小:
修改後進入src
並執行./make.bash
, 然後重新編譯目標程式, 運行:
可以看到當前環境下arena是512G, spans是512M, bitmap是16G.
這個方法雖然比較笨, 但是可以在任何情況下輸出我們想要的值.
此外, go運行時(runtime)的源代碼會包括在目標文件中,
例如你對runtime.newobject
下斷點可以對go自身的源代碼進行調試.
參考鏈接
https://golang.org
https://golang.org/doc/install/source
https://golang.org/doc/gdb
http://lldb.llvm.org/tutorial.html
http://legendtkl.com/archives
接下來我將分析golang的任務調度機制和三色GC的具體實現, 敬請期待.