Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 14125] ファイルの概要

コミット

commit 2100947d4a25dcf875be1941d0e3a409ea85051e
Author: Andrew Gerrand <adg@golang.org>
Date:   Thu Oct 11 14:21:19 2012 +1100

    doc/faq: discuss virtual memory use by go processes
    
    Fixes #3948.
    
    R=golang-dev, r, dave, dsymonds
    CC=golang-dev
    https://golang.org/cl/6639064

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/2100947d4a25dcf875be1941d0e3a409ea85051e

元コミット内容

このコミットは、Go言語のFAQドキュメント(doc/go_faq.html)に、Goプロセスによる仮想メモリの使用に関する説明を追加するものです。具体的には、Goプログラムが大量の仮想メモリを使用しているように見える理由と、実際のメモリ使用量を確認する方法について解説が加えられています。

変更の背景

この変更は、Go Issue #3948「doc/faq: explain large virtual memory usage」を修正するために行われました。多くのユーザーがGoプログラムを実行した際に、タスクマネージャーやtopコマンドなどで表示される仮想メモリ使用量が非常に大きいことに疑問を抱いていました。これは、Goのメモリ管理戦略、特にアロケータが仮想メモリを予約する方法に関する誤解が原因でした。

Goのランタイムは、効率的なメモリ管理のために、事前に大きな仮想メモリ領域を「アリーナ」として予約します。この予約は、実際にそのメモリが物理メモリに割り当てられているわけではなく、単に将来の割り当てのためにアドレス空間を確保しているに過ぎません。しかし、多くのシステム監視ツールは、この予約された仮想メモリ全体を「使用中」として報告するため、ユーザーはGoプログラムが不必要に大量のメモリを消費していると誤解していました。

この誤解を解消し、Goのメモリ管理の仕組みを正確に理解してもらうために、FAQドキュメントにこの説明を追加する必要がありました。

前提知識の解説

仮想メモリ (Virtual Memory)

仮想メモリは、オペレーティングシステム (OS) が物理メモリ(RAM)を抽象化し、アプリケーションに提供するメモリ管理技術です。各プロセスは、連続した広大な仮想アドレス空間を持っているかのように振る舞いますが、実際にはその一部だけが物理メモリにマッピングされています。

  • 仮想アドレス空間: 各プロセスが利用できる論理的なメモリ空間。
  • 物理メモリ (RAM): 実際にデータが格納されるハードウェアメモリ。
  • ページング: 仮想アドレス空間を固定サイズの「ページ」に分割し、物理メモリの「フレーム」にマッピングする仕組み。
  • スワップ領域: 物理メモリが不足した場合に、使用頻度の低いページを一時的にディスクに退避させる領域。

仮想メモリの利点は以下の通りです。

  1. メモリの抽象化: プログラムは物理メモリの配置を意識せずに、連続したアドレス空間としてメモリを利用できます。
  2. メモリ保護: 各プロセスの仮想アドレス空間は独立しており、他のプロセスのメモリにアクセスすることを防ぎます。
  3. メモリの効率的な利用: 実際に必要なページだけを物理メモリにロードし、不要なページはディスクに退避させることで、物理メモリを効率的に利用します。
  4. 大きなアドレス空間: 物理メモリの量に関わらず、より大きなアドレス空間をプログラムに提供できます。

メモリ予約 (Memory Reservation) と コミット (Memory Commitment)

仮想メモリの文脈では、「予約 (Reservation)」と「コミット (Commitment)」という概念が重要です。

  • メモリ予約 (Memory Reservation): プロセスが仮想アドレス空間の一部を将来の使用のために確保することです。この段階では、対応する物理メモリは割り当てられません。単に、そのアドレス範囲が他の目的で使用されないようにマークされるだけです。OSは、この予約されたアドレス範囲が利用可能であることを保証しますが、実際に物理メモリを割り当てるのは、そのアドレスにアクセスがあった時です。
  • メモリコミット (Memory Commitment): 予約された仮想メモリ領域に対して、実際に物理メモリ(またはスワップ領域)を割り当てることを指します。プログラムがその仮想アドレスに初めてアクセスした際に、OSがページフォルトを検出し、対応する物理ページを割り当てます。この段階で初めて、OSは物理メモリの空き状況を考慮します。

Goのメモリ管理では、この「予約」の段階で大きな仮想アドレス空間を確保するため、システム監視ツールが「使用中」と報告する仮想メモリの量が多くなります。しかし、これは「コミット」された物理メモリの量とは異なります。

Goのメモリ管理とアロケータ

Goランタイムは、独自のメモリ管理システム(ガベージコレクタとアロケータ)を持っています。Goのアロケータは、効率的なメモリ割り当てとガベージコレクションのために、ヒープ領域として使用する大きな仮想メモリ領域を事前に確保します。これは、将来のメモリ割り当て要求に迅速に対応できるようにするためです。

この戦略により、Goプログラムは頻繁なシステムコールを介してOSから小さなメモリチャンクを要求するのではなく、一度に大きな仮想メモリブロックを確保し、その中で独自にメモリを管理します。これにより、メモリ割り当てのオーバーヘッドが削減され、パフォーマンスが向上します。

技術的詳細

このコミットで追加されたFAQのセクションは、Goのメモリ管理の重要な側面を明確にしています。

Goのメモリ管理システムは、プログラムの実行効率を最大化するために、特定の戦略を採用しています。その一つが、仮想メモリの「アリーナ」としての予約です。

  1. 大きな仮想メモリ領域の予約: Goのメモリ・アロケータは、起動時に、将来のメモリ割り当てのために非常に大きな仮想メモリ領域を予約します。この領域は「アリーナ」と呼ばれ、Goプログラムが動的にメモリを確保する際の基盤となります。例えば、64ビットシステムでは、数GBから数十GBの仮想メモリを予約することが一般的です。
  2. 予約と物理メモリの分離: この予約は、あくまで仮想アドレス空間の確保であり、対応する物理メモリ(RAM)がすぐに割り当てられるわけではありません。物理メモリは、実際にその仮想アドレスにデータが書き込まれる(ページフォルトが発生する)までOSによって割り当てられません。
  3. 他のプロセスへの影響のなさ: 仮想メモリの予約は、そのGoプロセスにローカルなものであり、他のプロセスが利用できる物理メモリを奪うものではありません。OSは、物理メモリが実際に必要になったときにのみ割り当てを行います。
  4. 実際のメモリ使用量の確認方法: 多くのシステム監視ツール(例: Linuxのtopコマンド、macOSのtopコマンド)は、デフォルトで仮想メモリの総量(VIRTVSZ)を表示することがあります。しかし、Goプロセスが実際に使用している物理メモリの量を確認するには、topコマンドのRES(Resident Set Size、Linux)またはRSIZE(Resident Size、macOS)列を参照する必要があります。これらの値は、プロセスが現在物理メモリにロードしているページの合計サイズを示しており、Goプログラムの実際のメモリフットプリントをより正確に反映しています。

この説明は、Goプログラムのメモリ使用量に関する一般的な誤解を解消し、ユーザーがGoのパフォーマンス特性をより深く理解するのに役立ちます。

コアとなるコードの変更箇所

変更はdoc/go_faq.htmlファイルに対して行われました。具体的には、以下のHTMLスニペットが追加されています。

--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -1099,6 +1099,22 @@ analysis</em> recognizes some cases when such variables will not
 live past the return from the function and can reside on the stack.
 </p>
 
+<h3 id="Why_does_my_Go_process_use_so_much_virtual_memory">
+Why does my Go process use so much virtual memory?</h3>
+
+<p>
+The Go memory allocator reserves a large region of virtual memory as an arena
+for allocations. This virtual memory is local to the specific Go process; the
+reservation does not deprive other processes of memory.
+</p>
+
+<p>
+To find the amount of actual memory allocated to a Go process, use the Unix
+<code>top</code> command and consult the <code>RES</code> (Linux) or
+<code>RSIZE</code> (Mac OS X) columns.
+<!-- TODO(adg): find out how this works on Windows -->
+</p>
+
 <h2 id="Concurrency">Concurrency</h2>
 
 <h3 id="What_operations_are_atomic_What_about_mutexes">

コアとなるコードの解説

追加されたHTMLコードは、GoのFAQドキュメントに新しいセクション「Why does my Go process use so much virtual memory?」を導入しています。

  1. 見出し (<h3>):

    • id="Why_does_my_Go_process_use_so_much_virtual_memory": このIDは、FAQ内の特定のセクションへの直接リンクを可能にします。
    • テキスト「Why does my Go process use so much virtual memory?」は、ユーザーが抱くであろう疑問を直接的に提示しています。
  2. 最初の段落 (<p>):

    • 「The Go memory allocator reserves a large region of virtual memory as an arena for allocations.」: Goのメモリ・アロケータが、割り当てのための「アリーナ」として大きな仮想メモリ領域を予約するという核心的な説明です。
    • 「This virtual memory is local to the specific Go process; the reservation does not deprive other processes of memory.」: この予約がプロセスローカルであり、他のプロセスのメモリを奪うものではないことを強調し、一般的な懸念を払拭しています。
  3. 二番目の段落 (<p>):

    • 「To find the amount of actual memory allocated to a Go process, use the Unix top command and consult the RES (Linux) or RSIZE (Mac OS X) columns.」: ユーザーがGoプロセスの実際のメモリ使用量を確認するための具体的な手順を提供しています。topコマンドと、LinuxのRES、macOSのRSIZEという特定の列名を指定することで、実用的な情報を提供しています。
    • <!-- TODO(adg): find out how this works on Windows -->: Windows環境での確認方法が未定であることを示すコメントです。これは、将来の改善点として残されています。

この追加により、GoのFAQは、Goプログラムのメモリ使用量に関する一般的な誤解に対して、公式かつ明確な説明を提供するようになりました。

関連リンク

参考にした情報源リンク