使用dlv分析golang进程cpu占用高问题

c++通过dbg分析内存和cpu,可能大家都会。本篇主要分析通过delve分析golang程序cpu占用高的问题。
delve是golang推荐的专门go语言调试工具,用来替代gdb。golang组织说delve能更好的理解go语言。
先用vscode写个简单的demo,main.go代码如下:

package main

import (
	"fmt"
	"os"
	"os/signal"
)

func main() {
	fmt.Println("main start")

	msgList := make(chan int, 100)
	go func() {
		for {
			select {
			case <-msgList:
			default:

			}
		}
	}()
	
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	s := <-c
	
	fmt.Println("main exit.get signal:", s)
}

go build -o cpudetect main.go编译生成cpudetect并放到服务器运行。
接下来是具体的分析步骤:

一、top命令查看哪个进程:

top

Tasks: 168 total,   1 running, 166 sleeping,   1 stopped,   0 zombie
%Cpu(s): 94.4 us,  5.6 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   995684 total,    73064 free,   613904 used,   308716 buff/cache
KiB Swap:  2097148 total,  2093300 free,     3848 used.   200060 avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                                   
  7819 root      20   0  703020   1000    632 S 94.1  0.1   3:07.05 cpudetect                                                                                                                 
     1 root      20   0  128296   6704   3912 S  0.0  0.7   0:04.22 systemd                                                                                                                   
     2 root      20   0       0      0      0 S  0.0  0.0   0:00.01 kthreadd                                                                                                                  
     4 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kworker/0:0H 

可以看到cpudetect进程的cpu占用了94.1。

二、top -H -p 7819 命令查看进程cpudetect具体线程信息:

./dlv attach 7819

top - 01:36:29 up  3:18,  2 users,  load average: 0.68, 0.18, 0.18
Threads:   5 total,   1 running,   4 sleeping,   0 stopped,   0 zombie
%Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   995684 total,    73188 free,   613780 used,   308716 buff/cache
KiB Swap:  2097148 total,  2093300 free,     3848 used.   200184 avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                                   
  7823 root      20   0  703020   1000    632 R 99.3  0.1   0:50.62 cpudetect                                                                                                                 
  7819 root      20   0  703020   1000    632 S  0.0  0.1   0:00.00 cpudetect                                                                                                                 
  7820 root      20   0  703020   1000    632 S  0.0  0.1   0:00.06 cpudetect                                                                                                                 
  7821 root      20   0  703020   1000    632 S  0.0  0.1   0:00.01 cpudetect                                                                                                                 
  7822 root      20   0  703020   1000    632 S  0.0  0.1   0:00.00 cpudetect

可以看到主要由于线程7823占用cpu过高导致。

三、通过 ./dlv attach 7819 命令开启调试:

./dlv attach 7819

#使用goroutines命令查看所有的协程信息:
(dlv) goroutines
Goroutine 1 - User: E:/golang/cpuDetect/src/cpudetect/main.go:26 main.main (0x494212)
Goroutine 2 - User: c:/go/src/runtime/proc.go:305 runtime.gopark (0x431ae0)
Goroutine 3 - User: c:/go/src/runtime/proc.go:305 runtime.gopark (0x431ae0)
Goroutine 4 - User: c:/go/src/runtime/proc.go:305 runtime.gopark (0x431ae0)
Goroutine 5 - User: c:/go/src/runtime/proc.go:305 runtime.gopark (0x431ae0)
Goroutine 6 - User: E:/golang/cpuDetect/src/cpudetect/main.go:16 main.main.func1 (0x4942e4) (thread 7823)
Goroutine 7 - User: c:/go/src/runtime/sigqueue.go:147 os/signal.signal_recv (0x44559c)
Goroutine 8 - User: c:/go/src/runtime/proc.go:305 runtime.gopark (0x431ae0)

可以看到协程6挂在7823的线程下(7823是刚才cpu占用高的线程)。

 #切换到协程6并查看具体堆栈信息:
 (dlv) goroutine 6
 Switched from 6 to 6 (thread 7823)
 (dlv) bt
 0  0x0000000000405a89 in runtime.chanrecv
   at c:/go/src/runtime/chan.go:451
 1  0x0000000000405dca in runtime.selectnbrecv
   at c:/go/src/runtime/chan.go:646
 2  0x00000000004942e4 in main.main.func1
   at E:/golang/cpuDetect/src/cpudetect/main.go:16
 3  0x000000000045dad1 in runtime.goexit
   at c:/go/src/runtime/asm_amd64.s:1373

从上面的堆栈信息,可以定位到main.go 16行,再分析对应的代码,就可以确定是select中加了defualt但没有任何处理导致cpu空转,从而导致cpu过高。
另外,dlv调试还有很多其他的命令,大家自己通过help命令查看吧。

你可能感兴趣的:(使用dlv分析golang进程cpu占用高问题)