この場合のように、明示的な初期化子が指定されていないグローバル変数は、デフォルトで 0 に初期化されます。それらは.bss セグメントと呼ばれるメモリ領域に配置され、データの初期値を示すオブジェクト ファイル/実行可能ファイルに追加のデータは保存されません (初期値をどこかに保存する必要がある明示的に初期化されたデータとは異なります)。 .
OS がプログラムをロードすると、すべてのセグメントの記述が読み込まれ、そのためにメモリが割り当てられます。.bss セグメントがすべて 0 に初期化されることを認識しているため、実際に大量のメモリを割り当ててからすべて 0 に初期化する必要を回避するための巧妙なトリックを実行できます。プロセスのページ テーブル内のセグメントにアドレス空間を割り当てます。しかし、すべてのページが 0 で埋められた同じページを指しています。
その単一のゼロページも読み取り専用に設定されています。次に、プロセスが .bss セグメント内のデータに書き込むと、ページ フォールトが発生します。OS はページ フォールトをインターセプトし、何が起こっているかを把握してから、そのデータ ページに固有のメモリを実際に割り当てます。その後、命令を再開し、あたかもメモリが最初から割り当てられていたかのように、コードは順調に進みます。
したがって、ゼロで初期化されたグローバル変数または配列がある場合、最終的には、書き込まれることのない各ページ サイズのデータ チャンク (通常は 4 KB) に実際にメモリが割り当てられることはありません。
注: ここでは、「割り当てられた」という言葉を少し曖昧にしています。こういうことを掘り下げると、「予約」や「コミット」などの言葉が出てきそうです。Windows のコンテキストでのこれらの用語の詳細については、この質問とこのページを参照してください。