程式除錯對於檢查和理解程式執行過程和狀態是非常有用的。
乙個核心轉儲檔案( core dump file )中包含程式程序執行時的記憶體資訊和程序狀態。它主要用於程式的問題除錯,以及在執行過程中理解程式的狀態。這些對於我們診斷程式問題原因和分析生產環境中的服務問題有非常大的幫助。
在本文中,我會用乙個非常簡單的 hello world 網頁應用服務舉例,實際情況,我們的程式會更加複雜。對核心轉儲檔案的分析意義在於可以幫助我們檢視程式當時的運**況,並可能讓我們有機會重現當時的程式問題。
注意: 接下來的操作都是在linux系統終端中執行,我不確定其它類unix系統是否可以工作正常,macos 和 windows 應該都不支援。
在開始之前,你需要確定已經開啟了作業系統對核心轉儲檔案的支援。ulimit
的預設值為 0 意思是說核心轉儲檔案最大容量只能是零。我通常在開發機上設定為unlimited
命令如下:
$ ulimit -c unlimited
然後,確定你的機器上已經安裝了delve。
這是乙個main.go
檔案,包含乙個http啟動服務和乙個處理函式。
我們把它編譯成二進位制檔案。
$ go build .
我們假設下,將來這個服務可能會出現問題,但是你不知道會出現什麼樣的問題。你可能已經用了很多方法測試程式但仍然找不到程式異常退出的原因。
一般在這種情況下,最好能夠有當時程式程序的快照,然後用你的除錯工具對快照進行除錯。
有很多種方式可以獲得程式的核心轉儲檔案。你可能已經熟悉程式崩潰轉儲方式,當程式崩潰時會將崩潰時的程式核心資訊寫入磁碟檔案。go 預設是不開啟程式崩潰轉儲的,但是你可以設定gotraceback
為crash
來開啟 ctrl + backslash 生成崩潰轉儲檔案。
$ gotraceback=crash ./hello
(ctrl+)
這樣就可以使程式崩潰並將堆疊跟蹤列印寫入核心轉儲檔案。
另一種方法是從正在執行的程序中生成核心轉儲檔案,而不必殺死程序。使用gcore
選項就可以在不崩潰的情況下生成核心轉儲檔案。我們重新啟動程式:
$ ./hello &
$ gcore 546 # 546 is the pid of hello.
我們已經可以在程式不崩潰的情況下拿到核心轉儲檔案。下一步通過 delve 載入核心轉儲檔案進行分析。
$ dlv core ./hello core.546
這和 delve 的一般用法是相同的。你可以回放,檢視**,檢視變數等。有些功能會被禁用,畢竟核心轉儲檔案只是快照,而不是真實的程序情況,但程式的執行過程和程序狀態是完全可以訪問的。
(dlv) bt
0 0x0000000000457774 in runtime.raise
at /usr/lib/go/src/runtime/sys_linux_amd64.s:110
1 0x000000000043f7fb in runtime.diefromsignal
at /usr/lib/go/src/runtime/signal_unix.go:323
2 0x000000000043f9a1 in runtime.crash
at /usr/lib/go/src/runtime/signal_unix.go:409
3 0x000000000043e982 in runtime.sighandler
at /usr/lib/go/src/runtime/signal_sighandler.go:129
4 0x000000000043f2d1 in runtime.sigtrampgo
at /usr/lib/go/src/runtime/signal_unix.go:257
5 0x00000000004579d3 in runtime.sigtramp
at /usr/lib/go/src/runtime/sys_linux_amd64.s:262
6 0x00007ff68afec330 in (nil)
at :0
7 0x000000000040f2d6 in runtime.notetsleep
at /usr/lib/go/src/runtime/lock_futex.go:209
8 0x0000000000435be5 in runtime.sysmon
at /usr/lib/go/src/runtime/proc.go:3866
9 0x000000000042ee2e in runtime.mstart1
at /usr/lib/go/src/runtime/proc.go:1182
10 0x000000000042ed04 in runtime.mstart
at /usr/lib/go/src/runtime/proc.go:1152
(dlv) ls
> runtime.raise() /usr/lib/go/src/runtime/sys_linux_amd64.s:110 (pc: 0x457774)
105: syscall
106: movl ax, di // arg 1 tid
107: movl sig+0(fp), si // arg 2
108: movl $200, ax // syscall - tkill
109: syscall
=> 110: ret
111:
112: text runtime·raiseproc(sb),nosplit,$0
113: movl $39, ax // syscall - getpid
114: syscall
115: movl ax, di // arg 1 pid
go語言核心詳解
知道了不行,熟悉也不夠,要真正進入潛意識,成為條件反射才行!多讀書,多看報,少吃零食,多睡覺。golang基本語法中比較有含金量的技能點 1 鎖 2 反射 3 併發程式設計 var宣告變數 自動推導可以定義區域性變數 go語言和python語言一樣支援多返回值,也就是說函式可以一次性返回多個值,這和...
Go語言核心程式設計 09Map
map是key value資料結構,又稱為字段或者關聯陣列。var a map string string var a map string int var a map int string var a map string map string string value也是乙個map packag...
Go語言核心 slice切片
slice是長度可變的元素序列 陣列不可變 每個元素都有相同的型別。slice型別寫作t,其中t代表slice中的元素型別 slice和陣列寫法很像,只是沒有指定長度。陣列和slice之間的聯絡非常緊密。slice是非常輕量的資料結構,它是引用型別,指向底層的乙個陣列,該陣列被稱之為slice的底層...