ホームページ  >  記事  >  バックエンド開発  >  Golang マップ上で GC を実行することについて聞いたことがあるかもしれません。

Golang マップ上で GC を実行することについて聞いたことがあるかもしれません。

藏色散人
藏色散人転載
2021-08-13 14:26:462531ブラウズ

# Golang #のマップ構造は、キー値ペアを削除するときに実際に削除されず、マークされています。では、キーと値のペアが増えると、大量のメモリの無駄が発生するのでしょうか?

まず第一に、答えは「はい」です。OOM が発生する可能性が非常に高く、これについては github.com/golang/go/issues/20135 で議論されています。一般的な意味は、大規模な map では、delete 操作では実際にはメモリが解放されず、メモリ OOM が発生する可能性があるということです。

したがって、一般的なアプローチは、マップを再構築することですsafemap のコンテナ コンポーネントは go-zero に組み込まれています。 safemap これはある程度は回避できます。

まず、go が提供する map がどのように削除されるかを見てみましょう。

ネイティブ マップの削除

1  package main
2
3  func main() {
4      m := make(map[int]string, 9)
5      m[1] = "hello"
6      m[2] = "world"
7      m[3] = "go"
8
9      v, ok := m[1]
10     _, _ = fn(v, ok)
11
12     delete(m, 1)
13  }
14
15 func fn(v string, ok bool) (string, bool) {
16     return v, ok
17 }

テスト コードは上記のとおりです。 go tools apply -S -N -l testmap.go | grep " を渡すことができます。 CALL":

0x0071 00113 (test/testmap.go:4)        CALL    runtime.makemap(SB)
0x0099 00153 (test/testmap.go:5)        CALL    runtime.mapassign_fast64(SB)
0x00ea 00234 (test/testmap.go:6)        CALL    runtime.mapassign_fast64(SB)
0x013b 00315 (test/testmap.go:7)        CALL    runtime.mapassign_fast64(SB)
0x0194 00404 (test/testmap.go:9)        CALL    runtime.mapaccess2_fast64(SB)
0x01f1 00497 (test/testmap.go:10)       CALL    "".fn(SB)
0x0214 00532 (test/testmap.go:12)       CALL    runtime.mapdelete_fast64(SB)
0x0230 00560 (test/testmap.go:7)        CALL    runtime.gcWriteBarrier(SB)
0x0241 00577 (test/testmap.go:6)        CALL    runtime.gcWriteBarrier(SB)
0x0252 00594 (test/testmap.go:5)        CALL    runtime.gcWriteBarrier(SB)
0x025c 00604 (test/testmap.go:3)        CALL    runtime.morestack_noctxt(SB)

12 行目で delete を実行します。実際の実行は runtime.mapdelete_fast64 です。

これらの関数のパラメータの型は固有です int64mapdelete_fast64 は元の delete と同じように動作しますので、見てみましょうマップ削除

mapdelete

長い画像の警告! ! !

Golang マップ上で GC を実行することについて聞いたことがあるかもしれません。

#一般的なコード分析は上記のとおりで、具体的なコードは誰でも読めるように残されています。実際、一般的なプロセスは次のとおりです。

  1. 同時書き込みを防止するための書き込み保護
  2. 削除する key をクエリします (存在する場合)
  3. 存在する場合は、マークを削除するフラグを実行します
  4. count--

したがって、実際の広い領域の key を削除します。 map は保存されますが、key は削除されず、現在のキーのステータスが empty としてマークされるだけです。

実際、開始点は mysql のマークの削除に似ており、これにより今後同じ key が挿入されることがなくなり、拡張の必要がなくなります。そして縮小操作。

ただし、これは一部のシナリオでは不適切です。開発者が今後同じ key を挿入しない場合、OOM が発生する可能性があります。

そこで、上記の状況に対応して、go-zerosafemap を開発しました。 safemap がこの問題をどのように回避するかを見てみましょう。

safemap

操作から直接、このように設計されている理由を分析します。 safemap:

Golang マップ上で GC を実行することについて聞いたことがあるかもしれません。

  1. 削除しきい値を事前に設定します。トリガーされると、新しいプリセット newmap
  2. Two map に配置されます。は全体であるため、key は 1 つのコピーのみを保持できます

したがって、2 つの map を設定する必要がある理由は非常に明白です。

  1. dirtyOld ストレージ プリンシパルとして、delete 操作がしきい値に達すると移行がトリガーされます。
  2. dirtyNew 一時ストレージとして、しきい値に達すると、key/value

の一部が保存されます。 、移行操作中に行う必要があることは次のとおりです: 元の dirtyOld をクリアし、保存されたキー/値を for-range を介して dirtyNew に再度保存し、 dirtyNewdirtyOld を指します。

質問があるかもしれません: key/value は削除されないということですか? tophash=empty# とマークされているだけです。

##実際、

for-range プロセスでは、キー tophash がフィルターで除外されます

このようにして不要なキーが実現されます。

dirtyNew には追加されず、dirtyOld には影響しません。

Golang マップ上で GC を実行することについて聞いたことがあるかもしれません。

#これは実際には、旧世代と新世代のガベージ コレクションの概念です。

実装の詳細については、ソース コードを参照してください。

プロジェクト アドレス

github.com/tal-tech/go-zero

go-zero と

star## の使用へようこそ# 私たちを応援してください!

以上がGolang マップ上で GC を実行することについて聞いたことがあるかもしれません。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。