[golang]如何看懂調(diào)用堆棧

之前也有文章講過go調(diào)用堆棧的話題,但并沒有完全講清楚,這里補(bǔ)充里面缺漏的幾個(gè)點(diǎn)。

阻塞

goroutine 1 [select, 2 minutes]:

方括號(hào)里的select表示阻塞原因,具體定義見runtime.waitReason 。
后面的時(shí)間是阻塞時(shí)間。需要注意的是這只是一個(gè)大概時(shí)間,是在gc的過程中標(biāo)記的,所以如果這個(gè)goroutine不需要gc,那么永遠(yuǎn)也不會(huì)有值。

PC偏移

github.com/robfig/cron.(*Cron).run(0xc0000c44b0)
    cron.go:191 +0x28d

行號(hào)后面的16進(jìn)制數(shù)是什么?pc偏移。是指函數(shù)入口(cron.(*Cron).run)到調(diào)用處(也就是行號(hào)指位置)的指令位置偏差。一般很少用到,除非下面這種特殊情況:

func main() {
    rand.Seed(time.Now().UnixNano())
    _, _, _ = foo(), foo(), foo()
}

func foo() int {
    if rand.NormFloat64() > 0 {
        panic("")
    }
    return 0
}

//main.main()
//  main.go:10 +0x7b 或 +0x80 或 +0x85

函數(shù)參數(shù)

函數(shù)參數(shù)是最復(fù)雜的部分,牽涉到go的很多底層實(shí)現(xiàn)。

輸入?yún)?shù),輸出參數(shù)

為什么經(jīng)常只有一個(gè)參數(shù)的函數(shù)堆棧里卻跟著兩個(gè)數(shù)呢?另一個(gè)是輸出。

func main() {
    rand.Seed(time.Now().UnixNano())
    r := rand.Int() //2e78e7b163438cc2
    fmt.Printf("%x\n", r)
    foo(r)
}

func foo(i int) (o int) {
    o = rand.Int() //36dd26e720cac1fe
    fmt.Printf("%x\n", o)
    defer panic("want to panic")
    return
}

//main.foo(2e78e7b163438cc2, 36dd26e720cac1fe)
//  main.go:21 +0xdd
結(jié)構(gòu)體展開

結(jié)構(gòu)體會(huì)被展開,然后比較短的字段會(huì)被打包成一個(gè)uint。

type S struct {
    a int
    b int
    c int
    d int
    a1 bool
    b1 byte
    c1 bool
    d1 byte
}

func main() {
    foo(S{})
}

func foo(s S) {
    panic("want to panic")
    noInline()
}

func noInline() {
    fmt.Sprint()
}

//main.foo(0x0, 0x0, 0x0, 0x0, 0x0)
//  main.go:67 +0x39

但是這種打包是依賴字段順序的。

type S struct {
    a int
    a1 bool
    b int
    b1 bool
    c int
    c1 bool
    d int
    d1 bool
}

func main() {
    foo(S{})
}

func foo(s S) {
    panic("want to panic")
    noInline()
}

func noInline() {
    fmt.Sprint()
}

//main.foo(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
//  main.go:67 +0x39
函數(shù)參數(shù)對(duì)照表

下面的表涵蓋了大部分情況

函數(shù)簽名 輸入 堆棧輸出 說明
foo(float64) 1 (0x3ff0000000000000)
foo(complex64) 1+3i (0x404000003f800000) 兩個(gè)32位浮點(diǎn)打包為一個(gè)64位數(shù)
foo(complex128) 1+3i (0x3ff0000000000000, 0x4008000000000000)
foo(string) "中文" (0x10adc82, 0x6) (指針,字節(jié)數(shù))
foo(interface{}) "" (0x108e520, 0x10bff30) (類型指針,值指針)
foo(interface{}) (*string)(nil) (0x108b8e0, 0x0) 值為nil,類型不為nil
foo(interface{}) nil (0x0, 0x0) 值,類型都為nil
foo([]byte) make([]byte,3,6) (0xc000070f82, 0x3, 0x6) (指針,len,cap)
foo(map[string]string) make(map[string]string) (0xc000070e48)
foo(chan struct{}) make(chan struct{}) (0xc00005e060)
foo([200]int) [200]int{} (0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...) 數(shù)組展開
foo(func()) nil (0x0)
foo(int16, uint16) 1,2 (0xc000020001) 兩個(gè)16位數(shù)打包為32位數(shù),僅低32位有效
foo(bool)bool false (0xc000070f00, 0xc00005c058) 前一個(gè)數(shù)為輸入,僅低8位有效,后一個(gè)數(shù)為輸出,未初始化
foo(struct {a,b int}) struct {a,b int}{} (0x0, 0x0) 結(jié)構(gòu)體展開
foo(struct {a int;b bool;c int;d bool;e byte}) struct {a int;b bool;c byte;d bool;e byte}{1,true,2,false,3} (0x1, 0x1, 0x2, 0x300) d,e合并,b不合并
foo(struct {a int;b bool;c string;d bool;e byte}) struct {a int;b bool;c string;d bool;e byte}{1,true,"a",false,3} (0x1, 0x1, 0x10adb18, 0x1, 0x300) d,e合并
foo(struct {a struct{a,b byte};b bool}) struct {a struct{a,b byte};b bool}{struct{a,b byte}{3,4},true} (0xc000010403) 內(nèi)嵌結(jié)構(gòu)體合并
foo(struct {a struct{a int;b byte};b bool}) struct {a struct{a int;b byte};b bool}{struct {a int;b byte}{5 , 7 },false} (0x5, 0xc000072f07, 0xc00005e000) 內(nèi)嵌結(jié)構(gòu)體不合并
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、Python簡(jiǎn)介和環(huán)境搭建以及pip的安裝 4課時(shí)實(shí)驗(yàn)課主要內(nèi)容 【Python簡(jiǎn)介】: Python 是一個(gè)...
    _小老虎_閱讀 6,359評(píng)論 0 10
  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 14,264評(píng)論 0 38
  • 第二部分 自動(dòng)內(nèi)存管理機(jī)制 第二章 java內(nèi)存異常與內(nèi)存溢出異常 運(yùn)行數(shù)據(jù)區(qū)域 程序計(jì)數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)...
    小明oh閱讀 1,300評(píng)論 0 2
  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理,因此不免有一些不準(zhǔn)確的地方,同時(shí)不同JDK版本的...
    高廣超閱讀 16,074評(píng)論 3 83
  • 血在嘶吼, 盔甲在棄散, 我把尊嚴(yán)放入籃子 和死亡一起, 我曾用短刃刺穿暴怒, 曾流淚祈求苦難寬恕, 現(xiàn)在, 敵人...
    葡萄美酒閱讀 258評(píng)論 0 0

友情鏈接更多精彩內(nèi)容