【问题标题】:Do I need to set a map to nil in order for it to be garbage collected?我是否需要将地图设置为 nil 才能对其进行垃圾收集?
【发布时间】:2016-08-13 08:47:45
【问题描述】:

假设我有一个简单的映射,其中字符串作为键类型,自定义结构作为值类型。像这样:map[string]*struct

我用很多不同的值填充这张地图,并且这些值中的很多在一段时间后将永远不会再次使用。

所以我不确定 golang 垃圾收集器是否会为我清理我的地图,或者我需要自己清理。然后我在另一个问题上遇到了这个答案:Is it safe to remove selected keys from Golang map within a range loop?

这使得垃圾收集器看起来不会为我做这件事,我唯一的解决方案是如果我想不时释放一些内存,我的地图设置为 nil。

这是真的吗?还是有另一种方法可以做到这一点而不会丢失我的地图中非“非活动”的值?

【问题讨论】:

  • GC 收集所有无法访问的内存。地图和地图中删除的值都会被收集。地图结构可能会或可能不会被压缩,但这与正在收集的值是分开的。
  • 我不确定你在问什么。垃圾收集器不会删除地图中的条目,因为它们被地图引用(假设地图本身是可访问的)。如果地图中有不再需要的条目,则应将其删除。如果您将映射中特定键的值设置为 nil,则该映射条目指向的结构将被垃圾收集,假设它无法以其他方式访问。
  • 那么,verran 关于在stackoverflow.com/questions/36747776/… 中删除不释放内存的建议是不正确的?
  • @siebertschoutteten 你刚刚链接回这个问题。
  • 我想你指的是stackoverflow.com/a/23231539/152948——答案是肯定的和否定的。 bucket 永远不会被清理。如果映射存储了一个值类型(如int),则该int 的存储在存储桶内,因此除非您将映射归零,否则它也永远不会被清理。但是,如果地图正在存储指针,那么这意味着 指针的存储 将持续存在,但如果没有指向它,则指向的值将被 GC 处理。

标签: memory-management go garbage-collection


【解决方案1】:

您可以delete() 地图中的单个条目,即使在对其进行迭代时也是如此。如果该条目的值无法从其他任何东西中获取(并且它足够大),它们将被 GC'ed。

你看的问题引用了一些旧代码(你可以自己看源码),从map中移除对象后应该清空内存。

【讨论】:

  • 删除的代码从那时起并没有真正改变,只是从 C 翻译成 Go。这很重要,但它仍然没有合并存储桶。我认为 Verran 说的有点不准确,但基本上还是正确的。
  • 它可能引用了一些旧代码,但我找不到任何来源来证明你说的是真的?他们什么时候改的?我快速阅读了 go 1.5 和 1.6 发行说明,但找不到任何相关信息。
  • 我很确定 github.com/golang/go/blob/master/src/runtime/hashmap.go#L587 中的 memclr 会回收内存中的值。我认为 Verran 的信息关于键是准确的,但不是关于值的
  • @matt.s: memclr 将内存区域的字节归零,它不会为该值回收空间。运行play.golang.org/p/6NcaMtFaHyGODEBUG=gctrace=1,你会看到删除所有键后的集合什么都不做,并且直到可以收集映射值本身时堆才完全释放。
  • @JimB,我不确定。如果你给 GC 时间/需要工作,它看起来就像回收了大部分。如果你看这个例子play.golang.org/p/VanBaBR55K,为什么内存会下降?
【解决方案2】:

要尝试完全回答这个问题,我们需要弄清楚问题到底是什么。

对于标题问题:

我是否需要将映射设置为 nil 才能对其进行垃圾回收?

不,一旦映射值超出范围,它将像任何其他值一样被垃圾收集。

我用很多不同的值填充这个 [map[string]*stuct] 地图,其中很多值在一段时间后将永远不会再次使用。

您展示的这个示例地图包含指针值,只要它们包含在地图中,就永远不会收集它们指向的值。从映射中删除值(使用delete 或将键设置为另一个值)将允许收集指针引用的内存。不需要围绕地图进行特殊处理以确保垃圾回收。

现在,map 的内部结构目前还没有被压缩,小值(包括指针和 128 字节以下的任何内容)直接存储在哈希桶中。删除这些条目后,具有数百万条目的映射不会立即变小,因此如果您需要释放该内存,最好将您想要的剩余值复制到新映射。这类似于拥有一个除少数值外不再需要的大切片,您需要将剩余值复制到新切片以释放原始支持数组。

【讨论】:

  • 所以让我把这件事做对吧。如果我将剩余的值复制到新地图(我们在这里谈论数百万个条目)而不是什么都不做或删除不再需要的条目,它肯定会以一种很好的方式影响我的内存使用?
  • @siebertschoutteten:如果时间权衡对您来说是值得的,那么是的。回答这个问题的最好方法是简单地测试一下。
  • 这就是我需要知道的!
  • 你说“地图的内部结构没有被压缩”。我想这意味着现在删除的条目之前使用的内存块被保留了下来。然后这些是否被重新用于添加到地图中的新项目?如果是这样,那么在大多数情况下,仍然拥有它们不会成为问题。实际上,如果有的话,它可能会加速新的插入,因为这些内存块很容易获得。
猜你喜欢
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
  • 2016-05-19
  • 1970-01-01
相关资源
最近更新 更多