memory - Go:マップキーを再利用する場合のメモリ使用量の増加

memory map go

Goチュートリアルの一部として、複数のファイルの単語を数える簡単なプログラムを書いています。ファイルを処理してmap[string]intを作成するためのいくつかのgoルーチンがあり、特定の単語の出現回数がわかります。その後、マップは値を単一のマップに集約する削減ルーチンに送信されます。非常に簡単に聞こえ、Goの完璧な(map-reduce)タスクのように見えます。

160万のユニークな単語を含む約1万のドキュメントがあります。私が見つけたのは、コードの実行中にメモリ使用量が急速かつ絶えず増加していて、処理の約半分(12 GBボックス、7 GB空き)でメモリが不足していることです。つまり、この小さなデータセットにはギガバイトを使用します。

問題がどこにあるのかを突き止めようとしたところ、データを収集して集計しているレデューサーが原因であることがわかりました。これがコードです:

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)
}


上記のサンプルからマップを削除しても、メモリは妥当な制限(数百メガバイト)内にとどまります。私が見つけたのは、文字列のコピーを取ることでも問題が解決することです。つまり、次のサンプルは私の記憶を使い果たしません。

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に関しては直感が限られています。)それは望ましい動作ですか?私は何か間違ったことをしていますか?私は囲碁に失望すべきですか、それとも自分自身に失望すべきですか?

ありがとう!
答え
ファイルを文字列に変換するコードはどのように見えますか?そこで問題を探します。大きなブロック(ファイル全体か?)を文字列に変換し、それらを単語にスライスする場合、1つの単語を保存すると、ブロック全体が固定されます。ブロックを[]バイトとして保持し、それらを単語にスライスしてから、単語を個別に文字列型に変換してみてください。
関連記事

sockets - ErlangのTip&Tricksはgen_server sslソケットのメモリフットプリントを削減

windows - ページをディスクにスワップするタイミングを決定するためにWindowsメモリマネージャーが使用するしきい値は何ですか?

c++ - 36ビットを使用してマッピングされたIOにどのように対処しますか?

android - リストビューをスクロールするとメモリ使用量が大幅に増えるのはなぜですか?

mysql - MySQL InnoDBテーブルデータをメモリテーブルに同期する方法

c# - .NETアプリをすばやく起動するためのアプリケーション状態の記録と復元

ios - GLKitメモリリークcopywithZone

javascript - JavaScriptでのメモリ使用量の計算

java - アプリケーションが終了するとオブジェクトに何が起こるか

java - 大きなファイルを読み取り、Javaでいくつかの操作を実行する