小编典典

一旦被字节占用就无法释放内存

go

我收到compressedbytes[]
byte类型的压缩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()状态如下:

重置会将缓冲区重置为空,但会保留基础存储以供将来的写操作使用。重置与Truncate(0)相同。

如何取消设置缓冲区并再次释放内存?我的程序在运行2小时的过程中需要大约50MB的内存。当我导入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
}

阅读 699

收藏
2020-07-02

共1个答案

小编典典

一些事情要清除。Go是一种垃圾回收语言,这意味着当这些变量变得不可访问时,垃圾回收器会自动释放变量分配和使用的内存(如果您有另一个指向该变量的指针,则仍视为“可访问”)。

释放的内存并不意味着将其返回给操作系统。释放的内存意味着可以回收该内存,并在需要时将其重新用于另一个变量。因此,从操作系统中,您不会仅由于某些变量变得不可访问而垃圾回收器检测到此问题并释放了它使用的内存,就不会立即看到内存减少。

但是,如果Go运行时一段时间(通常约5分钟)不使用,它将把内存返回给OS。如果在此期间内存使用量增加(并且有选择地再次缩小),则很有可能不会将内存返回给操作系统。

如果您等待一段时间而不重新分配内存,则释放的内存最终将返回给OS(显然不是全部,而是未使用的“大块”)。如果您迫不及待想要发生这种情况,可以致电debug.FreeOSMemory()强制执行以下操作:

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

2020-07-02