go语言服务端内存持续增长,求解惑!

发布于 2022-09-01 05:49:38 字数 2791 浏览 18 评论 0

最近用golang开发了一个socket服务端,主要逻辑就是接收客户端发来的数据解析后存入opentsdb中,但是跑一段时间后发现内存就会增长,而且不会被gc回收,初步判定是由于大量make []byte 导致内存不释放,代码如下,求高人解惑?

func StartTCP() error {
    tcp_addr, _ := net.ResolveTCPAddr("tcp4", tcp_listen)
    listener, err := net.ListenTCP("tcp4", tcp_addr)
    if err != nil {
        return err
    }
    defer listener.Close()
    log.Info("start tcp listen on %s", tcp_listen)
    for {
        conn, err := listener.AcceptTCP()
        if err != nil {
            log.Error("accept error %s", err.Error())
            continue
        }
        log.Info("new session create %s", conn.RemoteAddr().String())
        go HandlerConn(conn)
    }
}


func ReadPacket(conn *net.TCPConn) []byte {
    head := make([]byte, 4)
    _, err := io.ReadFull(conn, head)
    if err != nil {
        return nil
    }
    size := binary.BigEndian.Uint32(head)
    data := make([]byte, size)
    _, err = io.ReadFull(conn, data)
    if err != nil {
        return nil
    }
    return data
}


func HandlerConn(conn *net.TCPConn) {
    addr := conn.RemoteAddr().String()
    defer func() {
        if err := conn.Close(); err != nil {
            log.Error("close session error %s", err.Error())
        } else {
            log.Info("session closed %s", addr)
        }
    }()
    for{
        data := ReadPacket(conn)
        if len(data) == 0 {
            log.Warn("empty data")
            return
        }
        go HandlerMsg(conn, data, t)
    }
}

附pprof信息

(pprof) top
9.92GB of 9.93GB total (  100%)
Dropped 359 nodes (cum <= 0.05GB)
  flat  flat%   sum%        cum   cum%
9.92GB   100%   100%     9.92GB   100%  main.ReadPacket
     0     0%   100%     9.92GB   100%  main.HandlerConn
     0     0%   100%     9.92GB   100%  runtime.goexit

(pprof) list main.ReadPacket
Total: 9.93GB
ROUTINE ======================== main.ReadPacket in /tmp/td-        server/tcp_server.go
9.92GB     9.92GB (flat, cum)   100% of Total
     .          .     30:       go HandlerConn(conn)
     .          .     31:   }
     .          .     32:}
     .          .     33:
     .          .     34:func ReadPacket(conn *net.TCPConn) []byte {
     .          .     35:   head := make([]byte, 4)
     .          .     36:   _, err := io.ReadFull(conn, head)
     .          .     37:   if err != nil {
     .          .     38:       return nil
     .          .     39:   }
     .          .     40:   size := binary.BigEndian.Uint32(head)
9.92GB     9.92GB     41:   data := make([]byte, size)
     .          .     42:   _, err = io.ReadFull(conn, data)
     .          .     43:   if err != nil {
     .          .     44:       return nil
     .          .     45:   }
     .          .     46:   return data
     .          .     47:}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

情愿 2022-09-08 05:49:38

后来opentsdb出过一次故障修复后就恢复正常了,内存使用维持在200M上下,pprof heap也稳定在2k左右,而且该现象也无法复现,只能判定是opentsdb的问题而导致内存不释放了。

诗化ㄋ丶相逢 2022-09-08 05:49:38

1) 你用的什么版本的go,尽量升级到最新版本的go,我做的sever也是make bytes去收包,未发现明显内存泄露
2) HandlerMsg是长连接还是短链接,如果是短连接的话,把相关的资源尝试释放下。

倥絔 2022-09-08 05:49:38

目前的代码上看应该就是HandlerMsg出问题了,看下是否这个函数没有返回过。

我的痛♀有谁懂 2022-09-08 05:49:38

handleMsg得贴出来 data释不释放取决于还有没有对象引用 另外这个程序有2个问题
1. conn在handleMsg里还需要使用 但很可能conn提前就被close了
2. 调用handleMsg没必要再起一个goroutine了吧

白馒头 2022-09-08 05:49:38

go HandlerMsg(conn, data, t)中的go去掉试试,我觉得可能是HandlerConn中定义了一个内部函数defer func(),它关闭conn后可能会导致HandlerMsg中的conn不可用,另外由于HandlerConn已经处于退出状态,而HandlerMsg是另外一个协程,其参数data使用data := ReadPacket(conn)中的data可能会有问题吧.

雨轻弹 2022-09-08 05:49:38
下面的代码就是泄露的根源,pprof提示的很清楚了
for{
    data := ReadPacket(conn)
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文