我正在处理一个非常大的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
是长度> 10的切片)。但是,内存没有释放,为什么?
答案 0 :(得分:1)
映射值&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
设置为零。先前由基础array
占用的内存将返回到垃圾回收器以供重用。
答案 1 :(得分:1)
地图大小限制为它在任何时候的最大大小。因为您存储的是指针(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{}
}