代码之家  ›  专栏  ›  技术社区  ›  Kevin P

释放结构图

go
  •  0
  • Kevin P  · 技术社区  · 7 年前

    我正在使用指向struct的指针的非常大的映射。它在程序的生命周期中不断增长(我将它用作缓冲区),我编写了一个函数,在调用它时应该减小它的大小。

    type S struct {
     a uint32
     b []uint32
    }
    
    s := make(map[uint32]*S)
    
    for k, v := range s {
      delete(s, k)
      s[k] = &S{a: v.a}
    }
    

    b 从地图的每个元素,所以我期望内存中地图的大小会缩小( b

    0 回复  |  直到 7 年前
        1
  •  1
  •   peterSO    7 年前

    地图值的大小 &S 指针是相同的,与片的容量无关 b .

    package main
    
    import (
        "fmt"
        "unsafe"
    )
    
    type S struct {
        a uint32
        b []uint32
    }
    
    func main() {
        size := unsafe.Sizeof(&S{})
        fmt.Println(size)
    
        size = unsafe.Sizeof(&S{b: make([]uint32, 10)})
        fmt.Println(size)
    
        s := make(map[uint32]*S)
    
        for k, v := range s {
            delete(s, k)
            s[k] = &S{a: v.a}
        }
    }
    

    8
    8
    

    切片在内部表示为

    type slice struct {
        array unsafe.Pointer
        len   int
        cap   int
    }
    

    &S{a: v.a} 你准备好了吗 b 初始值: array 到 nil 和 len cap 归零。以前由底层用户占用的内存 数组

        2
  •  1
  •   georgeok    7 年前

    地图大小限制为它在任何点上的最大大小。因为存储指针(map[uint32]*S)而不是值,所以删除的对象最终会被垃圾回收,但通常不会立即被回收,这就是为什么在类似top/htop的监视器中看不到它的原因。

    运行时足够聪明,如果系统没有压力或资源不足,它会保留内存供将来使用。

    https://stackoverflow.com/a/49963553/1199408 了解更多关于记忆的知识。

    在您的示例中,不需要调用delete。只需清除结构中的切片,就可以实现所需的功能。

    type S struct {
     a uint32
     b []uint32
    }
    
    s := make(map[uint32]*S)
    
    for k, v := range s {
      v.b = []uint32{}
    }