Go語言的堆棧分析

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

本文為理解翻譯,原文地址:http://www.goinggo.net/2015/01/stack-traces-in-go.html。牆內訪問

 

Introduction

在Go語言中有一些調試技巧能協助我們快速找到問題,有時候你想儘可能多的記錄異常但仍覺得不夠,搞清楚堆棧的意義有助於定位Bug或者記錄更完整的資訊。 本文將討論堆疊追蹤資訊以及如何在堆棧中識別函數所傳遞的參數。

Functions
先從這段代碼開始:
  Listing 1   01 package main
02
03 func main() {
04     slice := make([]string, 2, 4)
05     Example(slice, "hello", 10)
06 }
07
08 func Example(slice []string, str string, i int) {
09     panic("Want stack trace")
10 } Example函數定義了3個參數,1個string類型的slice, 1個string和1個integer, 並且拋出了panic,運行這段代碼可以看到這樣的結果:

  Listing 2   Panic: Want stack trace

goroutine 1 [running]:
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
        /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
        temp/main.go:9 +0x64
main.main()
        /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
        temp/main.go:5 +0x85

goroutine 2 [runnable]:
runtime.forcegchelper()
        /Users/bill/go/src/runtime/proc.go:90
runtime.goexit()
        /Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1

goroutine 3 [runnable]:
runtime.bgsweep()
        /Users/bill/go/src/runtime/mgc0.go:82
runtime.goexit()
        /Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1  堆棧資訊中顯示了在panic拋出這個時間所有的goroutines狀態,發生的panic的goroutine會顯示在最上面。

  Listing 3   01 goroutine 1 [running]:
02 main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
           /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
           temp/main.go:9 +0x64
03 main.main()
           /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
           temp/main.go:5 +0x85  第1行顯示最先發出panic的是goroutine 1, 第二行顯示panic位於main.Example中, 並能定位到該行代碼,在本例中第9行引發了panic。 下面我們關注參數是如何傳遞的:

  Listing 4   // Declaration
main.Example(slice []string, str string, i int)

// Call to Example by main.
slice := make([]string, 2, 4)
Example(slice, "hello", 10)

// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)  這裡展示了在main中帶參數調用Example函數時的堆棧資訊,比較就能發現兩者的參數數量並不相同,Example定義了3個參數,堆棧中顯示了6個參數。現在的關鍵問題是我們要弄清楚它們是如何匹配的。 第1個參數是string類型的slice,我們知道在Go語言中slice是參考型別,即slice變數結構會包含三個部分:指標、長度(Lengthe)、容量(Capacity)

  Listing 5   // Slice parameter value
slice := make([]string, 2, 4)

// Slice header values
Pointer:  0x2080c3f50
Length:   0x2
Capacity: 0x4

// Declaration
main.Example(slice []string, str string, i int)

// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)  因此,前面3個參數會匹配slice, 如所示:

  Figure 1     figure provided by Georgi Knox
 我們現在來看第二個參數,它是string類型,string類型也是參考型別,它包括兩部分:指標、長度。

  Listing 6   // String parameter value
"hello"

// String header values
Pointer: 0x425c0
Length:  0x5

// Declaration
main.Example(slice []string, str string, i int)

// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)  可以確定,堆棧資訊中第4、5兩個參數對應代碼中的string參數,如所示:

  Figure 2     figure provided by Georgi Knox
 最後一個參數integer是single word值。

  Listing 7   // Integer parameter value
10

// Integer value
Base 16: 0xa

// Declaration
main.Example(slice []string, str string, i int)

// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)  現在我們可以符合代碼中的參數到堆棧資訊了。

  Figure 3     figure provided by Georgi Knox

Methods
 如果我們將Example作為結構體的方法會怎麼樣呢?

  Listing 8   01 package main
02
03 import "fmt"
04
05 type trace struct{}
06
07 func main() {
08     slice := make([]string, 2, 4)
09
10     var t trace
11     t.Example(slice, "hello", 10)
12 }
13
14 func (t *trace) Example(slice []string, str string, i int) {
15     fmt.Printf("Receiver Address: %p\n", t)
16     panic("Want stack trace")
17 } 
如上所示修改代碼,將Example定義為trace的方法,並通過trace的執行個體t來調用Example。
 再次運行程式,會發現堆棧資訊有一點不同:

  Listing 9   Receiver Address: 0x1553a8
panic: Want stack trace

01 goroutine 1 [running]:
02 main.(*trace).Example(0x1553a8, 0x2081b7f50, 0x2, 0x4, 0xdc1d0, 0x5, 0xa)
           /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
           temp/main.go:16 +0x116

03 main.main()
           /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
           temp/main.go:11 +0xae  首先注意第2行的方法調用使用了pointer receiver,在package名字和方法名之間多出了"*trace"字樣。另外,參數列表的第1個參數標明了結構體(t)地址。我們從堆棧資訊中看到了內部實現細節。

Packing
如果有多個參數可以填充到一個single word, 則這些參數值會合并打包:

  Listing 10   01 package main
02
03 func main() {
04     Example(true, false, true, 25)
05 }
06 
07 func Example(b1, b2, b3 bool, i uint8) {
08     panic("Want stack trace")
09 } 這個例子修改Example函數為4個參數:3個bool型和1個八位無符號整型。bool值也是用8個bit表示,所以在32位和64位架構下,4個參數可以合并為一個single word。

  Listing 11   01 goroutine 1 [running]:
02 main.Example(0x19010001)
           /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
           temp/main.go:8 +0x64
03 main.main()
           /Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
           temp/main.go:4 +0x32 這是本例的堆棧資訊,看的具體分析:

  Listing 12   // Parameter values
true, false, true, 25

// Word value
Bits    Binary      Hex   Value
00-07   0000 0001   01    true
08-15   0000 0000   00    false
16-23   0000 0001   01    true
24-31   0001 1001   19    25

// Declaration
main.Example(b1, b2, b3 bool, i uint8)

// Stack trace
main.Example(0x19010001)  以上展示了參數值是如何匹配到4個參數的。當我們看到堆棧資訊中包括十六進位值,需要知道這些值是如何傳遞的。

Conclusion
The Go runtime provides a great deal of information to help us debug our programs. In this post we concentrated on stack traces. The ability to decode the values that were passed into each function throughout the call stack is huge. It has helped me more than once to identify my bug very quickly. Now that you know how to read stack traces, hopefully you can leverage this knowledge the next time a stack trace happens to you.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.