ホームページ >バックエンド開発 >Golang >Go が長さ 100k の配列よりも長さ 100k のスライスの方が使用するメモリが少ないのはなぜですか?

Go が長さ 100k の配列よりも長さ 100k のスライスの方が使用するメモリが少ないのはなぜですか?

王林
王林転載
2024-02-09 10:12:09504ブラウズ

为什么 Go 对于长度为 100k 的切片使用的内存比长度为 100k 的数组要少?

Go 言語がスライスと配列を処理する場合、長さ 100k のスライスは長さ 100k の配列よりもメモリ使用量が少なくなります。これは、スライスでは基礎となる実装でポインタと長さの組み合わせが使用されるのに対し、配列ではデータを格納するために連続したメモリ領域が必要になるためです。スライスの長さは可変であるため、メモリは動的に割り当ておよび解放できますが、配列は宣言時に固定長を指定する必要があります。したがって、大量のデータを処理する場合、スライスを使用するとメモリ空間をより効率的に使用し、メモリ使用量を削減できます。これは、大規模なデータを処理する場合の Go 言語の利点の 1 つでもあります。

質問の内容

次のコードを考えてみましょう。それぞれ長さ 100k の 4000 個の配列を割り当てました。 リーリー

プログラムをローカルで実行してメモリ使用量を分析すると、2 GB を超えるメモリが使用され始めます。

ここで、コードを少し変更して、次のように配列スライス (ただし長さは 100k) を使用するとします。

リーリー

私のマシンでは、メモリは約 73mb でピークに達しました。 ###何故ですか?

次の理由により、両方のフラグメントがほぼ同じメモリを使用すると思います:

どちらの場合も、go ランタイムは
    parentmap
  • の値をヒープに割り当てます。 go がこれを行うのは、これらの値をスタックに割り当てると、現在の関数がスコープ外になると parentmap の値がすべてクリアされるためです。 したがって、最初のコード スニペットは 4k 配列をヒープに直接割り当てます。
  • そして、2 番目のフラグメントは、ヒープ上に 4k スライス ヘッダーを割り当てます。各スライス ヘッダーには、サイズ 100k の一意の配列 (ヒープ上にもあります) へのポインターがあります。
  • どちらの場合も、サイズ 100k のヒープ上に 4k の配列があります。したがって、どちらの場合もほぼ同じ量のメモリを使用する必要があります。
  • 読みました: https://go.dev/blog/slices-intro。しかし、これを説明する実装の詳細は見つかりません。

回避策

スライスを使用するバージョンでは、遅延割り当ての利点が得られる可能性があります。これらのスライスのいずれかにあるデータ バッファーへの書き込みは何も試行されないため、実際に書き込みが試行されるまで、オペレーティング システムはこれらのバッファーに実際にメモリを割り当てなくても構いません。 (オペレーティング システムは、割り当てが強制されないようにバッファのゼロ初期化を遅らせることもできます。)

一方、配列を使用するバージョンでは、配列を実際にマップにコピーする必要があります。これは、実際に書き込みを実行することを意味します。書き込まれた値がすべて 0 であっても、それらは書き込みであることに変わりはないため、オペレーティング システムは書き込まれるデータ用にメモリを実際に割り当てる必要があります。

これらのスライスにデータを書き込もうとすると、スライスされたバージョンもギガバイトのメモリを占有するはずです。 (メモリのページごとに 1 つの値で十分だと思いますが、スライスに

1

を設定する方が簡単かもしれません。)

以上がGo が長さ 100k の配列よりも長さ 100k のスライスの方が使用するメモリが少ないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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