一旦被bytes.Buffer占用就无法释放内存

时间:2016-05-23 04:19:49

标签: memory go buffer zlib

我在[]字节的compressedbytes中接收压缩ASCII文本的字节。我面临的问题是,以下过程占用了大量内存,这些内存在函数到达终点后没有被释放,并且在程序的整个运行时期间仍然被占用。

    b := bytes.NewReader(compressedbytes)
    r, err := zlib.NewReader(b)
    if err != nil {
        panic(err)
    }
    cleartext, err = ioutil.ReadAll(r)
    if err != nil {
        panic(err)
    }

我注意到使用的类型是bytes.Buffer,此类型具有Reset()Truncate()函数,但它们都不允许释放曾经占用的内存。

Reset()的{​​{3}}声明如下:

  

重置将缓冲区重置为空,但它会保留底层存储空间以供将来的写入使用。重置与截断(0)相同。

如何取消缓冲区并再次释放内存? 我的程序在运行期间需要大约50MB的内存,需要2小时。当我导入zlib压缩的字符串时,程序需要200 MB的内存。

感谢您的帮助。

===更新

我甚至为解压缩创建了一个单独的函数,并在程序从该函数返回后用runtime.GC()手动调用垃圾收集器,但没有成功。

// unpack decompresses zlib compressed bytes
func unpack(packedData []byte) []byte {
    b := bytes.NewReader(packedData)
    r, err := zlib.NewReader(b)
    if err != nil {
        panic(err)
    }
    cleartext, err := ioutil.ReadAll(r)
    if err != nil {
        panic(err)
    }
    r.Close()
    return cleartext
}

2 个答案:

答案 0 :(得分:24)

有些事要清楚。 Go是一种垃圾收集语言,这意味着当这些变量变得无法访问时,垃圾收集器会自动释放由变量分配和使用的内存(如果你有另一个指向变量的指针,那么它仍然计为"可达" )。

释放内存并不意味着它被返回到操作系统。释放内存意味着可以回收内存,如果需要可以重用另一个变量。因此,从操作系统中你不会立即看到内存减少只是因为某些变量无法访问而垃圾收集器检测到它并释放了它所使用的内存。

然而,如果一段时间(通常大约5分钟)没有使用,Go运行时会将内存返回给操作系统。如果在此期间内存使用量增加(并且可选择再次收缩),则内存很可能不会返回到操作系统。

如果你等待一段时间而不再重新分配内存,最终将释放内存(显然不是全部,但未使用的"大块"将会)。如果您不能等待这种情况发生,您可以致电debug.FreeOSMemory()强制执行此操作:

  

FreeOSMemory强制进行垃圾收集,然后尝试尽可能多地将内存返回给操作系统。 (即使未调用此选项,运行时也会在后台任务中逐渐将内存返回给操作系统。)

查看这种陈旧但非常有用的问题+答案:

Go 1.3 Garbage collector not releasing server memory back to system

答案 1 :(得分:3)

当没有任何东西引用它时它最终会被释放,Go有一个相当不错的GC。