dongxieli3839
2014-01-12 21:41
浏览 82
已采纳

Go http标准库中的内存泄漏?

Have a Go binary implement an http server:

package main

import (
    "net/http"
)

func main() {
    http.ListenAndServe(":8080", nil)
}

It will start with ~850 kb or so of memory. Send it some requests via your web browser. Observe it quickly rises to 1 mb. If you wait, you'll see it never goes down. Now hammer it with Apache Bench (using the script below) and see your memory usage continually increase. After sometime it will eventually plateau at around 8.2 MB or so.

Edit: It doesn't seem to stop at 8.2, rather it slows down significantly. It's currently at 9.2 and still rising.

In short, why is this happening? I used this shell script:

while [ true ]
do
    ab -n 1000 -c 100 http://127.0.0.1:8080/
    sleep 1
end

While trying to get to the bottom of this, I've tried to tweak the settings. I've tried closing using r.Close = true to prevent Keep-Alive. Nothing seems to work.

I found this originally while trying to determine if there was a memory leak in a program I'm writing. It has a lot of http handlers and I/O calls. After checking I had closed all my database connections I kept seeing it's memory usage rise. My program to plateau at around 433 MB.

Here's the output of Goenv:

GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/mark/Documents/Programming/Go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
TERM="dumb"
CC="clang"
GOGCCFLAGS="-g -O2 -fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fno-common"
CXX="clang++"
CGO_ENABLED="1"

图片转代码服务由CSDN问答提供 功能建议

使用Go二进制文件实现http服务器:

 包 main 
 
import(
“ net / http” 
)
 
func main(){
 http.ListenAndServe(“:8080”,nil)
} 
    
 
 

它将以大约850 kb的内存开头。 通过网络浏览器发送一些请求。 观察它很快上升到1 mb。 如果您等待,您将看到它永远不会失败。 现在,使用Apache Bench(使用下面的脚本)对其进行锤击,以查看您的内存使用量在不断增加。 一段时间后,它将最终稳定在8.2 MB左右。

编辑:它似乎并没有停止在8.2 MB处,而是大大降低了速度。 当前是9.2,并且还在上升。

简而言之,为什么会这样? 我使用了以下shell脚本:

 ,而[true] 
do 
 ab -n 1000 -c 100 http://127.0.0.1:8080/
 sleep 1 \  nend 
   
 
 

在尝试深入了解这一点时,我尝试调整设置。 我尝试使用 r.Close = true 关闭以防止Keep-Alive。 似乎没有任何作用。

我最初是在尝试确定正在编写的程序中是否存在内存泄漏时发现此问题的。 它具有许多http处理程序和I / O调用。 在检查完所有数据库连接后,我继续看到它的内存使用量增加。 我的程序稳定在 433 MB 左右。

以下是Goenv的输出:

  GOARCH =“  AMD64 “
GOBIN =” “
GOCHAR =” 6 “
GOEXE =” “
GOHOSTARCH =” AMD64 “
GOHOSTOS =” 达尔文 “
GOOS =” 达尔文 “
GOPATH =”/用户/标记/文档/编程/转到 “
GORACE =” “
GOROOT =” 在/ usr /本地/去 “
GOTOOLDIR =” 在/ usr /本地/去/包装/工具/ darwin_amd64 “\ NTERM =” 哑巴 “\ NCC =” 铛 “
GOGCCFLAGS =”  -g -O2 -fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fno-common“ 
CXX =” clang ++“ 
CGO_ENABLED =” 1“ 
   
 <  / DIV>
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • doujian1050 2014-01-12 23:32
    已采纳

    From the heap pprof you have provided in comments, it looks like you are leaking memory via gorilla/sessions and gorilla/context (almost 400MB).

    Refer to this ML thread: https://groups.google.com/forum/#!msg/gorilla-web/clJfCzenuWY/N_Xj9-5Lk6wJ and this GH issue: https://github.com/gorilla/sessions/issues/15

    Here is a version that leaks extremely quickly:

    package main
    
    import (
        "fmt"
        // "github.com/gorilla/context"
        "github.com/gorilla/sessions"
        "net/http"
    )
    
    var (
        cookieStore = sessions.NewCookieStore([]byte("cookie-secret"))
    )
    
    func main() {
        http.HandleFunc("/", defaultHandler)
        http.ListenAndServe(":8080", nil)
    }
    
    func defaultHandler(w http.ResponseWriter, r *http.Request) {
        cookieStore.Get(r, "leak-test")
        fmt.Fprint(w, "Hi there")
    }
    

    Here is one that cleans up and has a relatively static RSS:

    package main
    
    import (
        "fmt"
        "github.com/gorilla/context"
        "github.com/gorilla/sessions"
        "net/http"
    )
    
    var (
        cookieStore = sessions.NewCookieStore([]byte("cookie-secret"))
    )
    
    func main() {
        http.HandleFunc("/", defaultHandler)
        http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))
    }
    
    func defaultHandler(w http.ResponseWriter, r *http.Request) {
        cookieStore.Get(r, "leak-test")
        fmt.Fprint(w, "Hi there")
    }
    
    打赏 评论

相关推荐 更多相似问题