返回信息流我的一个线上程序,出现内存泄露问题,运行3-5天后内存居高不下,远超出该程序本应该占用的内存,我把出问题的这段代码贴出来,请大家帮忙看一下问题所在
```Go
package main
import (
"io"
"io/ioutil"
"net"
"net/http"
_ "net/http/pprof"
"net/url"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
)
func run(addr string) {
ln, err := reuse.Listen("tcp", addr)
if err != nil {
log.Error("error listening %v, %v\n", addr, err)
return
}
log.Info("server listening at %v ...\n", addr)
for {
conn, err := ln.Accept()
if err != nil {
log.Error("accept error: %v\n", err)
return
}
go handleConnection(conn)
}
}
type GateServerConn struct {
appId string
sessionId string
closed bool
gateChan chan *util.LeakyBuf
sessionChan chan *util.LeakyBuf
keepAliveChan chan *util.LeakyBuf
sessionClientChanSize int
bandWidth uint16
}
func handleConnection(conn net.Conn) {
/*
省略部分代码
*/
gateServerConn = &GateServerConn{
appId: appId,
sessionId: sessionId,
closed: false,
/*第55行*/ gateChan: make(chan *util.LeakyBuf, common.GateChanSize),
keepAliveChan: make(chan *util.LeakyBuf, 100),
sessionClientChanSize: 0,
bandWidth: uint16(bandWidth * 10),
}
gateServerConnMapMutex.Lock()
gateServerConnMap[sessionId] = gateServerConn
gateServerConnMapMutex.Unlock()
sessionChanMapMutex.RLock()
sessionChan, ok := sessionChanMap[sessionAddr]
sessionChanMapMutex.RUnlock()
if !ok {
sessionChanMapMutex.Lock()
/*第68行*/ sessionChan = make(chan *util.LeakyBuf, common.SessionChanSize)
sessionChanMap[sessionAddr] = sessionChan
sessionChanMapMutex.Unlock()
go startSessionProxy(sessionAddr, sessionChan)
}
gateServerConn.sessionChan = sessionChan
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer func() {
if err := recover(); err != nil {
log.Error("%v %s->%s:gate server recv failed:%v\n", gateServerConn.sessionId, conn.RemoteAddr(), conn.LocalAddr(), err)
}
}()
defer func() {
gateServerConn.closed = true
conn.Close()
util.SafeClose(gateServerConn.gateChan)
util.SafeClose(gateServerConn.keepAliveChan)
wg.Done()
}()
readTimeout := time.Duration(common.GateServerReadTimeout) * time.Second
var buf *util.LeakyBuf
for !gateServerConn.closed {
// 省略业务逻辑代码
}
}()
wg.Wait()
closeSession(session_id)
}
func startSessionProxy(session_server_addr string, sessionChan chan *util.LeakyBuf) {
// 省略业务逻辑代码
}
var config util.Config
var log util.Logger
var leakyBufPool = util.NewLeakyBufPool(util.MaxNBuf, util.LeakyBufSize)
var gateServerConnMap map[string]*GateServerConn
var sessionChanMap map[string]chan *util.LeakyBuf
var gateServerConnMapMutex *sync.RWMutex
var sessionChanMapMutex *sync.RWMutex
var whiteIPList string
func main() {
// 省略部分代码
go run(serverAddr)
util.WaitSignal()
}
```
在程序运行一段时间后,我使用go pprof查看goroutine和heap使用情况,发现heap异常:
heap profile: 15926: 918443936 [252871: 990891280] @ heap/1048576
15393: 630497280 [15559: 637296640] @ 0x40f4f1 0x4054b3 0x403a95 0x401dc3 0x468961 0x4054b2 main.createSessionWithUrl+0x1992
0x403a94 main.createSession+0x1a4
0x401dc2 main.handleConnection+0x9d2
35: 280125440 [35: 280125440] @ 0x40f4f1 0x40574e 0x403a95 0x401dc3 0x468961 0x40574d main.createSessionWithUrl+0x1c2d
0x403a94 main.createSession+0x1a4
0x401dc2 main.handleConnection+0x9d2
这是heap的使用情况,可以看到这两个heap占用内存比较大,第一个heap有15393个对象,对应代码第55行,第2个heap有35个对象,对应代码第68行。
然后我查看goroutine情况,发现确实有35个startSessionProxy的goroutine,这符合我们的期望, 但是handleConnection这个goroutine只有694个,按道理一个handleConnection的goroutine应该对应一个gateServerConn对象, 也就是一个gateServerConn.gateChan对象,而我们看heap信息得到的gateChan数量是15393, 远远对不上,数毫无疑问是有内存泄露存在,但是我没有找到什么地方存在泄露,请大家帮忙看看!
这是一条镜像帖。来源:北邮人论坛 / golang / #763同步于 2017/2/19
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Golang机器人发帖
请大家帮忙看一个内存泄露的问题
asm
2017/2/19镜像同步2 回复
订阅后,新回复会通过你的通知中心匿名送达。
2 条回复
不是,遇到错误会改成true,这段被我省略掉了
问题已经找到了,是closeSession(session_id)中没有正确清理gateServerMap导致gateServerConn的引用一直存在
【 在 wanghaohebe 的大作中提到: 】
: gateServerConn.closed这个永远都是false?