go-zookeeper / zk

Native ZooKeeper client for Go
BSD 3-Clause "New" or "Revised" License
504 stars 130 forks source link

Method zk.Connect causes memory leak #140

Closed wzlove closed 2 months ago

wzlove commented 2 months ago

After my zk node data experiences several changes. I discovered a memory leak through the flame graph. image

image

code case :

    if err != nil {
        fmt.Println("connect zk err", err.Error())
    }
    node := "/test"
    go func() {
    loop:
                zkConn, _, err := zk.Connect([]string{"127.0.0.1:2181"}, 5*time.Second)
        for {
            _, _, ch, err := zkConn.ChildrenW(node)
            if err != nil {
                fmt.Println(fmt.Errorf("%s zk watch have error,%s", node, err.Error()))
                return
            }
            evt := <-ch
            if evt.Type == zk.EventSession {
                if evt.State == zk.StateConnecting {
                    continue
                }
                // reconnecting
                if evt.State == zk.StateExpired {
                    fmt.Println("Zookeeper session expired, reconnecting")
                }
            }
            switch evt.Type {
            case
                zk.EventNodeCreated,
                zk.EventNodeDeleted,
                zk.EventNodeChildrenChanged,
                zk.EventNodeDataChanged:
                fmt.Println("refresh zk", evt.State, evt.Type)
                goto loop
            }
            continue

        }
    }()
    select {}
wzlove commented 2 months ago

I've solved it. better code is

zkConn, _, err := zk.Connect([]string{"127.0.0.1:2181"}, 5*time.Second)
    if err != nil {
        fmt.Println("connect zk err", err.Error())
    }
    node := "/test"
    go func() {
    loop:
        for {
            _, _, ch, err := zkConn.ChildrenW(node)
            if err != nil {
                fmt.Println(fmt.Errorf("%s zk watch have error,%s", node, err.Error()))
                return
            }
            for evt := range ch {
            switch evt.Type {
            case
                zk.EventNodeCreated,
                zk.EventNodeDeleted,
                zk.EventNodeChildrenChanged,
                zk.EventNodeDataChanged:
                goto loop
                return
            }
            continue
        }
    }()
    select {}