memory - Go:重用映射键时会占用大量内存

标签 memory dictionary go

作为我的 Go 教程的一部分,我正在编写简单的程序来计算多个文件中的单词数。我有一些 go 例程用于处理文件并创建 map[string]int 来告诉已找到特定单词的出现次数。然后,该映射被发送到减少例程,该例程将值聚合到单个映射。听起来非常简单,看起来像是 Go 的完美(map-reduce)任务!

我有大约 10k 文档,其中包含 160 万个唯一单词。我发现,在运行代码时,我的内存使用量不断快速增长,并且在处理过程的一半时内存就耗尽了(12GB 盒子,7GB 可用空间)。所以是的,这个小数据集使用千兆字节!

试图找出问题所在,我发现归咎于收集和聚合数据的 reducer 。代码如下:

func reduceWords (input chan map[string]int, output chan int) {
  total := make(map[string]int)
  for wordMap := range input {
    for w, c := range wordMap {
      total[w] += c
    }
  }      
  output <- len(total)
}

如果我从上面的示例中删除 map ,内存将保持在合理的限制内(几百兆字节)。但我发现,复制字符串也可以解决问题,即以下示例不会耗尽我的内存:

func reduceWords (input chan map[string]int, output chan int) {
  total := make(map[string]int)
  for wordMap := range input {
    for w, c := range wordMap {
      copyW := make([]byte, len(w)) // <-- will put a copy here!
      copy(copyW, w)
      total[string(copyW)] += c
    }
  }  
  output <- len(total)
}

当我直接使用该值时,是否有可能在每次迭代后都没有破坏 wordMap 实例? (作为一名 C++ 程序员,我对 GC 的直觉有限。)这是理想的行为吗?难道我做错了什么?我应该对 Go 失望还是对自己失望?

谢谢!

最佳答案

将文件转换为字符串的代码是什么样的?我会在那里寻找问题。如果您要将大块(可能是整个文件?)转换为字符串,然后将它们 slice 为单词,那么如果您保存任何一个单词,则您将固定整个 block 。尝试将 block 保留为 []byte,将它们 slice 为单词,然后将单词单独转换为字符串类型。

关于memory - Go:重用映射键时会占用大量内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10376755/

相关文章:

c - 如何使用纯 C(而不是 C++)中的已知地址分配一 block 内存

c++ - 使用cgroup来限制资源

Python 获取字典中的最高值

python - 从 go 调用 python 回调指针

URL 查询字符串中的 golang 和映射

c - 函数中的 Malloc 和 free(优化你的内存)

c++ - cudaDeviceSynchronize() 错误代码 77 : cudaErrorIllegalAddress

python - 具有单独 TTL 的过期字典

java - 我们可以将嵌套 map 作为其他 map 中的键吗?

map 某部分的Golang for循环