当前位置: 首页 > 知识库问答 >
问题:

golang websocket内存泄漏

齐涛
2023-03-14

我们有一个基于go-socket.io(socket.ioGo语言实现)和大猩猩网络插座的网络插座服务,但是似乎有内存泄漏问题。即使我使用调试,HeapAlloc也总是在增加。FreeOSMemroy强制释放内存。

服务很简单。它将使用jwt令牌对传入请求进行身份验证,如果身份验证成功,则将创建一个go套接字。io conn基于gorilla websocket conn。但现在似乎是net/textproto。(*阅读器)。ReadMIMEHeader(包含在net/http.readRequest中,位于net/http.(*conn)中)。serve)占用了大量内存,这让我很困惑,因为当请求劫持到websocket conn时,net/http。(*康涅狄格州)。戈鲁廷马上回来。

  1. 堆使用中的调用图

https://lh3.googleusercontent.com/-mm2uAP5ihFM/V9IVWSlqUFI/AAAAAAAAAFc/8lLdQ3XgKCgeuCxQN81VQ8U5mDJcQxvWQCLcB/s1600/heap_in_use.png

https://lh3.googleusercontent.com/-zKpnnKowYcc/V9IV5Ncxs3I/AAAAAAAAAFg/hcptQ-bmiwsmRbFYnvTEB9jNylbJ8nh3gCLcB/s1600/heap_alloc.png



gc 440 @51045.897s 0%: 0.034+4182+0.96 ms clock, 0.13+0/4182/12246+3.8 ms cpu, 4304->4309->4143 MB, 8266 MB goal, 4 P
scvg340: inuse: 4404, idle: 15, sys: 4419, released: 0, consumed: 4419 (MB)
GC forced
gc 441 @51170.096s 0%: 3.7+4355+1.4 ms clock, 14+2.9/4357/12795+5.8 ms cpu, 4317->4323->4158 MB, 8287 MB goal, 4 P
GC forced
gc 442 @51294.460s 0%: 0.034+3987+1.2 ms clock, 0.13+1.5/3987/11701+4.9 ms cpu, 4336->4341->4169 MB, 8316 MB goal, 4 P
scvg341: inuse: 4318, idle: 133, sys: 4451, released: 0, consumed: 4451 (MB)
GC forced
gc 443 @51418.451s 0%: 0.36+3925+0.99 ms clock, 1.4+4.0/3925/11554+3.9 ms cpu, 4350->4356->4182 MB, 8338 MB goal, 4 P
scvg342: inuse: 4363, idle: 103, sys: 4466, released: 0, consumed: 4466 (MB)
GC forced
gc 444 @51542.394s 0%: 0.042+3986+1.6 ms clock, 0.16+0/3981/11757+6.5 ms cpu, 4361->4367->4194 MB, 8365 MB goal, 4 P
scvg343: inuse: 4404, idle: 74, sys: 4478, released: 0, consumed: 4478 (MB)
GC forced
gc 445 @51666.384s 0%: 3.4+3987+1.4 ms clock, 13+2.5/3986/11747+5.7 ms cpu, 4375->4382->4208 MB, 8388 MB goal, 4 P
scvg344: inuse: 4454, idle: 39, sys: 4493, released: 0, consumed: 4493 (MB)
GC forced
gc 446 @51790.379s 0%: 0.055+4147+1.5 ms clock, 0.22+0/4139/12125+6.2 ms cpu, 4396->4402->4220 MB, 8416 MB goal, 4 P
scvg345: inuse: 4509, idle: 5, sys: 4514, released: 0, consumed: 4514 (MB)
GC forced
gc 447 @51914.542s 0%: 0.052+4205+2.1 ms clock, 0.21+1.5/4199/12348+8.5 ms cpu, 4413->4420->4234 MB, 8441 MB goal, 4 P
GC forced
gc 448 @52038.752s 0%: 2.7+4517+1.8 ms clock, 11+2.3/4517/13245+7.2 ms cpu, 4428->4436->4247 MB, 8469 MB goal, 4 P
scvg346: inuse: 4406, idle: 142, sys: 4548, released: 0, consumed: 4548 (MB)
GC forced
gc 449 @52163.276s 0%: 0.033+4206+1.3 ms clock, 0.13+0/4206/12306+5.3 ms cpu, 4442->4449->4259 MB, 8495 MB goal, 4 P
scvg347: inuse: 4452, idle: 109, sys: 4561, released: 0, consumed: 4561 (MB)
GC forced
gc 450 @52287.491s 0%: 0.044+4262+2.0 ms clock, 0.17+0/4261/12565+8.2 ms cpu, 4452->4459->4272 MB, 8519 MB goal, 4 P
scvg348: inuse: 4498, idle: 74, sys: 4572, released: 0, consumed: 4572 (MB)
GC forced
gc 451 @52411.769s 0%: 0.028+4012+2.0 ms clock, 0.11+0.066/3992/11762+8.0 ms cpu, 4471->4477->4285 MB, 8544 MB goal, 4 P
scvg349: inuse: 4550, idle: 40, sys: 4590, released: 0, consumed: 4590 (MB)

代码示例

func (c *CometServer) initHTTPServer() {

jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
        SigningMethod: jwt.SigningMethodHS256,
        ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
                return []byte(setting.JwtSecret), nil
        },

        // get token from header, querystring, and cookie
        Extractor: jwtmiddleware.FromFirst(
                jwtmiddleware.FromParameter(setting.JwtTokenQueryStringField),
                TokenFromCookie(setting.JwtTokenCookieField),
                jwtmiddleware.FromAuthHeader,
        ),
        ErrorHandler: jwtErrorHandler,
})

r := mux.NewRouter()
// Must call cotext.Clear after every request follow
r.KeepContext = true

socketHandler := jwtMiddleware.Handler(c.socketio)

r.Handle("/socket.io/", socketHandler)

if setting.DEBUG {
        r.PathPrefix("/debug/").Handler(http.DefaultServeMux)
        r.PathPrefix("/").Handler(http.FileServer(http.Dir("./asset/")))
}

// n.UseHandler(r)

c.httpServer = &http.Server{
        Addr:    setting.HTTPListenAddr,
        Handler: r,
}

}

// .... // 去插座。io代码//。。。。func(c*CometServer)initSocketIO()错误{server,err:=socketio.NewServer(transports),如果err!=nil{return err}

// ....

server.On("error", func(so socketio.Socket, err error) {
        logger := SocketLogger(so)
        logger.Error("socket connect error")
})

服务器On(“连接”,func(so socketio.Socket){

        var (
                uid   string
                exist bool
        )

        logger := SocketLogger(so)

        claim := (context.Get(so.Request(), "user")).(*jwt.Token).Claims
        // after get the claims, should clear the request context
        context.Clear(so.Request())

        var rawUID interface{}
        if user, ok := claim.(jwt.MapClaims); ok {
                if rawUID, ok = user[setting.JwtUserClaimField]; !ok {
                        logger.Error("invalid user claim")
                        so.Emit("disconnect", "invalid user claim")
                }
        } else {
                logger.Errorf("invalid jwt claim %s", claim)
                so.Emit("disconnect", "invalid user claim")
        }

        if uid, exist = rawUID.(string); exist {
                // Multi connection for same user will be join to the same room
                so.Join(uid)

                // root for broadcast all user
                so.Join(Hourse)

                c.users.Add(uid, 1)

                logger.Debug("socket connected")

                if setting.DEBUG {
                        so.Emit("debug", fmt.Sprintf("Your uid is %s, sid is %s", uid, so.Id()))
                }
        } else {
                so.Emit("disconnect", "invalid user claim")
        }

        so.On("debug", func(data string) {
                log.Debugf("debug data from client %s", data)
        })

        so.On("disconnection", func(data string) {
                logger.Debugf("socket disconnected")
                c.users.Add(uid, -1)
        })
})
c.socketio = server

return nil

}

共有1个答案

吴举
2023-03-14

最后我解决了这个问题。

我使用https://github.com/auth0/go-jwt-middleware使用JWT进行身份验证。我还将gorilla mux路由器的KeepContext打开为true,这样可以从gorilla上下文获取请求的jwt令牌。当我获得jwt令牌时,将立即清除请求上下文(通过context.clear(r))。到目前为止,一切正常。但是当go jwt中间件身份验证失败时,就没有机会清除请求上下文,因为mux的KeepContext已变为true。这是根本原因。

 类似资料:
  • 问题内容: 我认为我的android应用正在泄漏内存。我不是绝对确定这是问题所在。 应用程序打开时经常崩溃,并且logcat尝试加载位图图像时会显示“内存不足”异常。 崩溃后,我重新打开了该应用程序,它运行正常。Logcat会显示许多“ gc”,并且JIT表会不时地向上调整大小,而不会向下调整,直到应用程序因内存不足错误而崩溃。 这听起来像是内存泄漏吗?如果是这样,我该如何定位和关闭泄漏点。 这是

  • 问题内容: 我一直在追寻内存泄漏(由“ valgrind –leak-check = yes”报告),它似乎来自ALSA。这段代码已经存在于自由世界中一段时间​​了,所以我猜这是我做错的事情。 输出看起来像这样: 并继续一些页面 这是由于我在一个项目中使用ALSA并开始看到这种巨大的泄漏……或者至少是所说泄漏的报告。 所以问题是:是我,ALSA或valgrind在这里遇到问题吗? 问题答案: ht

  • 问题内容: 我有一个长时间运行的脚本,如果让脚本运行足够长的时间,它将消耗系统上的所有内存。 在不详细介绍脚本的情况下,我有两个问题: 是否有可遵循的“最佳实践”,以防止泄漏发生? 有什么技术可以调试Python中的内存泄漏? 问题答案: 看看这篇文章:跟踪python内存泄漏 另外,请注意,垃圾收集模块实际上可以设置调试标志。看一下功能。此外,请查看Gnibbler的这段代码,以确定调用后已创建

  • 本文向大家介绍Java 内存泄漏,包括了Java 内存泄漏的使用技巧和注意事项,需要的朋友参考一下 在Java中,垃圾回收(析构函数的工作)是使用垃圾回收自动完成的。但是,如果代码中有引用它们的对象怎么办?它无法取消分配,即无法清除其内存。如果这种情况一再发生,并且创建或引用的对象根本没有被使用,它们就会变得无用。这就是所谓的内存泄漏。 如果超过了内存限制,则程序将通过抛出错误(即“ OutOfM

  • 问题内容: 我使用Informix遇到了一个奇怪的问题(具体来说,我使用的是IBM.Data.Informix命名空间,即4.10 Client SDK)。我正在使用ODBC连接到IBM Informix数据库,并且遇到内存泄漏问题。该文档相当稀疏,并且我只能使用当前安装的驱动程序/ SDK。这是我用于数据库上下文的代码: } 我已尝试处置并关闭所有可以的连接,但这似乎无济于事。我是否缺少某些东西

  • 问题内容: 我发现使用是众所周知的与相关的内存问题。 使用中是否存在内存泄漏? 如果是,解决方法是什么? 以下链接显示了Java中子字符串的正确用法。 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4513622 另外一个博客谈论子字符串中可能的MLK。 http://nflath.com/2009/07/the-dangers-of- st