生产环境下的FreeOSMemory()

11

我正在一个有TCP服务器的包中使用goroutines。大多数情况下,响应非常重,但当例行程序结束后,它并没有从内存中清除。

func Handle() {
    service := ":7777"
    tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
    checkError(err)
    listener, err := net.ListenTCP("tcp", tcpAddr)
    checkError(err)
    defer listener.Close()

    for {
        conn, err := listener.Accept()
        checkError(err)
        go handleRequest(conn, db)

    }
}

func handleRequest(conn net.Conn, db *sql.DB) {
    message := make([]byte, 0, 4096)
    tmp := make([]byte, 256)
    n, err := conn.Read(tmp)
    if err != nil {
        if err != io.EOF {
            fmt.Println("read error:", err)
        }
    }
    message = append(message, tmp[:n]...)
    fmt.Println("Message Received:", string(message))
    // do something to get resp
    conn.Write(append(resp, []byte("\n")...))
    conn.Close()
    debug.FreeOSMemory()
    return
}

所以在这种情况下,响应很大,一个 goroutine 使用了 10% 的内存,这是可以的,因为我从数据库中获取了 170,000 个用户并将结果解析为 JSON。但是当 handleRequest 仍然在内存中时,如果我不使用 debug.FreeOsMemory(),我对此持怀疑态度,因为它在调试包中,所以我的问题是:清空 goroutines 正在使用的内存是否是一种好方法?我测试过了,它不会影响系统,并且工作得非常好。如果不是,请问什么是好方法?我不能等待 GC 来清理它吗?!我阅读了这篇文章,这就是我开始使用它的原因,在第一个答案中有最后的建议。


不是。远离这样的黑客行为,特别是因为它们没有帮助。 - Volker
2
@Volker 首先,为什么我被踩了?其次,那么什么是好的方法呢? - PumpkinSeed
4个回答

10
Go运行时不会立即将空闲内存释放回操作系统,这样做是低效的。在这里了解更多信息:Golang - Cannot free memory once occupied by bytes.Buffer
你应该让Go运行时处理这个问题。如果你的应用程序在不调用debug.FreeOsMemory()的情况下不稳定,那么就有更大的问题,即使它“表面上”有所帮助,也不应该掩盖这些问题。甚至可能会让事情变得更糟,因为如果服务请求确实需要大量内存(当请求完成后由GC正确释放),调用FreeOsMemory()将只会将其返回给操作系统,而当再次服务另一个请求时,运行时将不得不再次请求/分配它。如果没有将其归还给操作系统,则可以在下一个请求中使用它...
尝试减少请求处理程序的内存需求。如果不可能(值得怀疑),则限制可能同时服务于大内存请求的数量。

查看这个问题+答案,了解如何操作:Go Web服务器的进程管理

另外:在Go中,这是一个惯用的工作线程池吗?


谢谢,没有使用FreeOSMemory服务后,这个服务变得稳定了。我只是不知道这是否是一个好的方法。现在我有头绪了。 - PumpkinSeed

4
作为偶尔调用 debug.FreeOsMemory() 的替代方案,您可以通过 GOGC 环境变量或 debug.SetGCPercent() 方法来控制垃圾回收器的侵略性。
从经验上看,即使将值设置为10,也足以完成其工作。
请参见runtime 包

3

是的,我读到了,这就是为什么我开始使用这个软件包,但是由于主要软件包的名称,我有些疑虑,这是正确的方法吗? - PumpkinSeed
如果你需要立即释放内存,这是一个好的方法,但在所有编程语言中强制释放内存都是危险的。 - Manuel Luis Garrido Gutiérrez

0

这太疯狂了,我认为这是golang的一个bug,我的代码包括:

go func() {
    for {
        debug.FreeOSMemory()
        log4sys.Warn("NumGoroutine:",runtime.NumGoroutine())
        time.Sleep(1 * time.Minute)
    }
}()

解决这个问题


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接