miller
发布于

go dlv debug 进程

类似gdb LLDB
只有 Delve 是专门为 Go 语言设计开发的调试工具. 线上debug break断点.

  1. 定位到函数某行,还可以。一直输入goroutines 能能看到哪里hang住。
  2. 看哪些goroutine运行什么,bt也可以。
  3. 看汇编...
    go install github.com/go-delve/delve/cmd/dlv@latest

提供个hang死code

package main

import (
    "fmt"
    "math/rand"
    "strconv"
    "sync"
    "time"
)

type AllData struct {
    data      map[*Conn]*Conn
    dLock     sync.RWMutex
    closeChan chan *Conn
}

type Conn struct {
    Name string
    Id   int
    tag  bool
}

func main() {
    allData := &AllData{
        data:      make(map[*Conn]*Conn, 10),
        closeChan: make(chan *Conn, 5),
    }

    go allData.addTest()
    go allData.waitfordie()

    go func() {
        interval := 100 * time.Millisecond
        timer := time.NewTimer(interval)
        for {
            select {
            case <-timer.C:
                allData.rangeForTest()
                timer.Reset(interval)
            }
        }
    }()

    go func() {
        interval := 3 * time.Millisecond
        timer := time.NewTimer(interval)
        for {
            select {
            case <-timer.C:
                allData.addTest()
                timer.Reset(interval)
            }
        }
    }()

    for {
        time.Sleep(10 * time.Second)
    }
}

func (a *AllData) rangeForTest() {
    a.dLock.RLock()
    defer a.dLock.RUnlock()
    for key := range a.data {
        if key.Id%5 == 0 {
            if key.tag {
                fmt.Println("in again")
                continue
            } else {
                key.tag = true
                a.closeChan <- key // todo 这里阻塞
                fmt.Println("rangeForTest in ", len(a.closeChan), time.Now())
            }
        }
    }
    fmt.Println("rangeForTest ", time.Now())
}

func (a *AllData) addTest() {
    a.dLock.Lock()
    intn := rand.Intn(1000)
    //fmt.Println(">>>>>>>>>>>>>>>>>>", "addTest", intn)
    c := &Conn{
        Name: "this is test :" + strconv.Itoa(intn),
        Id:   intn,
        tag:  false,
    }
    a.data[c] = c
    a.dLock.Unlock()
    //fmt.Printf("allData len %d\n", len(a.data))
}

func (a *AllData) deleteConn(c *Conn) {
    a.dLock.Lock()
    defer a.dLock.Unlock()
    delete(a.data, c)
    fmt.Println("deleteConn", c.Id, time.Now())
}

func (a *AllData) waitfordie() {
    for {
        select {
        case c := <-a.closeChan: // todo func deletechan can't get lock
            fmt.Println("accept close info :", c.Id, ">>>>>>>>>>> len:", len(a.closeChan))
            a.deleteConn(c) // 上边range 一边往里放, 拿着锁, 这里删不掉,满了。 又拿不到锁
        }
    }
}

参考
教程
更详细的

  • go build v2main.go
  • pidof v2main 或者ps -ef| grep v2main
  • dlv attach 8796
  • goroutines 看到多少协程
  • goroutine 【number】 切换到别的协程上

  • 都是系统goroutine
  • bt 打印调用堆栈 stack
  • disass 反编译查看汇编
浏览 (564)
点赞
收藏
评论