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

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

このコミットは、GoランタイムがNetBSDオペレーティングシステム上でメモリ管理を改善するために、SysUnused関数にMADV_FREEアドバイスを実装したものです。これにより、Goのガベージコレクタが不要になったメモリ領域をOSに解放する際に、より効率的なヒントを提供できるようになります。具体的には、madviseシステムコールをNetBSD向けに利用し、MADV_FREE定数を追加し、関連するアセンブリコードを修正しています。

コミット

commit 4047f300c9defec5b0fc0d6801f29c03c4873af9
Author: Joel Sing <jsing@google.com>
Date:   Mon Nov 26 22:34:01 2012 +1100

    runtime: implement SysUnused for netbsd
    
    R=golang-dev, bradfitz, minux.ma, dave
    CC=golang-dev
    https://golang.org/cl/6842081
---
 src/pkg/runtime/defs_netbsd.go      |  2 ++\
 src/pkg/runtime/defs_netbsd_386.h   |  2 ++\
 src/pkg/runtime/defs_netbsd_amd64.h |  2 ++\
 src/pkg/runtime/mem_netbsd.c        |  4 +---\
 src/pkg/runtime/sys_netbsd_386.s    |  9 ++++++++-\
 src/pkg/runtime/sys_netbsd_amd64.s  | 12 +++++++++++-\
 6 files changed, 26 insertions(+), 5 deletions(-)

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

https://github.com/golang/go/commit/4047f300c9defec5b0fc0d6801f29c03c4873af9

元コミット内容

runtime: implement SysUnused for netbsd

R=golang-dev, bradfitz, minux.ma, dave
CC=golang-dev
https://golang.org/cl/6842081

変更の背景

Go言語のランタイムは、ガベージコレクタ(GC)によってメモリを自動的に管理します。GCが不要になったメモリ領域を特定した後、その物理メモリをオペレーティングシステム(OS)に返却することで、システム全体のメモリ効率を向上させる必要があります。この返却処理は、Goランタイムのruntime.SysUnused関数を通じて行われます。

以前のNetBSD向けのruntime.SysUnusedの実装では、USED(v); USED(n);というプレースホルダのようなコードが含まれており、実際にはOSに対してメモリの解放を通知する具体的なシステムコールが呼び出されていませんでした。コメントには// TODO(rsc): call madvise MADV_DONTNEEDとあり、将来的にmadviseシステムコールを使ってMADV_DONTNEEDを呼び出す計画があったことが示唆されています。

このコミットは、NetBSD環境においてruntime.SysUnusedが実際に機能するように、madviseシステムコールとMADV_FREEアドバイスを導入することで、この未実装部分を解決することを目的としています。これにより、Goプログラムが使用しなくなったメモリをOSがより効率的に再利用できるようになり、特にメモリ使用量が多いGoアプリケーションのパフォーマンスとシステム全体の安定性が向上します。

前提知識の解説

madviseシステムコール

madvise()は、プロセスが仮想メモリシステムに対して、特定のメモリ範囲をどのように使用する予定であるかについてヒントを与えるためのシステムコールです。このヒントは、カーネルがメモリ管理を最適化し、アプリケーションのパフォーマンスを向上させるのに役立ちます。ただし、カーネルはこれらのヒントを無視することもできます。

madvise(void *addr, size_t len, int behav)という形式で呼び出され、addrはメモリ範囲の開始アドレス、lenはその長さ、behavは期待されるメモリの振る舞いを示すアドバイス値です。

MADV_DONTNEEDMADV_FREE

madviseシステムコールには、様々なアドバイス値があります。このコミットで特に重要なのは以下の2つです。

  • MADV_DONTNEED: このアドバイスは、指定されたメモリ範囲のページが近い将来アクセスされないことを示します。OSはこれらのページを解放し、物理メモリを再利用することができます。次にアクセスがあった場合、ページは再度ロードされるか、ゼロフィルされます。これは即座にメモリを解放する傾向があります。
  • MADV_FREE: NetBSDを含む一部のOSでサポートされているMADV_FREEは、指定されたメモリ範囲の情報がもはや重要ではないことを仮想メモリシステムに伝えます。これは「遅延解放」を意味し、カーネルはメモリ圧力がかかったときにこれらのページを後で再利用できます。もしアプリケーションが解放される前にページにアクセスしようとした場合、元のデータがまだ存在していればそれが提供されます。しかし、ページが既に再利用されていれば、新しいゼロフィルされたページが提供されます。MADV_DONTNEEDと比較して、MADV_FREEはメモリ割り当て器にとってより効率的なメモリ管理を可能にし、実際のページ解放を必要になるまで遅らせることができます。

runtime.SysUnused

runtime.SysUnusedはGoランタイムの内部関数であり、Goプログラムが特定のメモリ領域をもう使用しないことをオペレーティングシステムに通知する役割を担っています。Goのガベージコレクタがメモリを回収した後、一定期間(例えば5分間)使用されていないメモリブロック(スパン)がある場合、Goランタイムはこのruntime.SysUnusedを呼び出します。この関数は通常、madviseのようなシステムコールをMADV_DONTNEEDMADV_FREEといったフラグと共に使用して、OSに物理ページを再利用できることを伝えます。ただし、これは物理メモリの即時解放を保証するものではなく、OSがいつこれらのページを実際に再利用するかはOSの判断に委ねられます。

技術的詳細

このコミットの主要な変更点は、NetBSDにおけるGoランタイムのメモリ管理、特にruntime.SysUnused関数の動作を改善することにあります。

  1. MADV_FREE定数の追加:

    • src/pkg/runtime/defs_netbsd.gosrc/pkg/runtime/defs_netbsd_386.hsrc/pkg/runtime/defs_netbsd_amd64.hの各ファイルに、MADV_FREE定数が追加されました。これは、madviseシステムコールで使用するMADV_FREEアドバイスの値をGoランタイムが認識できるようにするためです。NetBSDではMADV_FREEの値は0x6です。
  2. runtime.SysUnusedの実装変更:

    • src/pkg/runtime/mem_netbsd.c内のruntime·SysUnused関数が修正されました。以前は単にUSED(v); USED(n);というダミーのコードとTODOコメントがあっただけでしたが、この変更によりruntime·madvise(v, n, MADV_FREE);が呼び出されるようになりました。これは、指定されたメモリ範囲vとサイズnに対して、MADV_FREEアドバイスを用いてmadviseシステムコールを呼び出すことを意味します。これにより、Goランタイムは不要になったメモリをOSに効率的に通知できるようになります。
  3. runtime·madviseアセンブリ関数の追加:

    • src/pkg/runtime/sys_netbsd_386.s (32ビット版) と src/pkg/runtime/sys_netbsd_amd64.s (64ビット版) に、TEXT runtime·madvise(SB)という新しいアセンブリ関数が追加されました。
    • これらのアセンブリ関数は、GoのCコードから呼び出されるruntime·madvise関数が、実際にNetBSDのmadviseシステムコールを呼び出すためのラッパーとして機能します。
    • 32ビット版 (sys_netbsd_386.s):
      • MOVL $75, AX:システムコール番号75(NetBSDにおけるsys_madviseの番号)をAXレジスタにロードします。
      • INT $0x80:ソフトウェア割り込み0x80を発生させ、システムコールを実行します。
      • JAE 2(PC):システムコールが成功した場合(キャリーフラグがクリアされている場合)、エラー処理をスキップします。
      • MOVL $0xf1, 0xf1:システムコールが失敗した場合、クラッシュを意図した命令を実行します。
    • 64ビット版 (sys_netbsd_amd64.s):
      • MOVQ addr+0(FP), DI:第一引数addrDIレジスタにロードします。
      • MOVQ len+8(FP), SI:第二引数lenSIレジスタにロードします。
      • MOVQ behav+16(FP), DX:第三引数behavDXレジスタにロードします。
      • MOVQ $75, AX:システムコール番号75をAXレジスタにロードします。
      • SYSCALL:システムコールを実行します。
      • JCC 2(PC):システムコールが成功した場合(キャリーフラグがクリアされている場合)、エラー処理をスキップします。
      • MOVL $0xf1, 0xf1:システムコールが失敗した場合、クラッシュを意図した命令を実行します。

これらの変更により、GoランタイムはNetBSD上で不要なメモリをOSに効率的に通知し、OSがそのメモリを再利用できるようにすることで、メモリフットプリントの削減とパフォーマンスの向上に貢献します。

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

  • src/pkg/runtime/defs_netbsd.go: MADV_FREE定数の追加。
  • src/pkg/runtime/defs_netbsd_386.h: 32ビット版NetBSD向けのMADV_FREE定数の追加。
  • src/pkg/runtime/defs_netbsd_amd64.h: 64ビット版NetBSD向けのMADV_FREE定数の追加。
  • src/pkg/runtime/mem_netbsd.c: runtime·SysUnused関数内でruntime·madviseを呼び出すように変更。
  • src/pkg/runtime/sys_netbsd_386.s: 32ビット版NetBSD向けのruntime·madviseアセンブリ関数の追加。
  • src/pkg/runtime/sys_netbsd_amd64.s: 64ビット版NetBSD向けのruntime·madviseアセンブリ関数の追加。

コアとなるコードの解説

src/pkg/runtime/defs_netbsd.go

@@ -37,6 +37,8 @@ const (
 	MAP_PRIVATE = C.MAP_PRIVATE
 	MAP_FIXED   = C.MAP_FIXED
 
+	MADV_FREE = C.MADV_FREE
+
 	SA_SIGINFO = C.SA_SIGINFO
 	SA_RESTART = C.SA_RESTART
 	SA_ONSTACK = C.SA_ONSTACK

この変更は、Goの定数としてMADV_FREEを追加しています。C.MADV_FREEは、C言語のヘッダファイルからインポートされたMADV_FREEの値を使用することを意味します。これにより、GoコードからMADV_FREEをシンボリックに参照できるようになります。

src/pkg/runtime/defs_netbsd_386.h および src/pkg/runtime/defs_netbsd_amd64.h

@@ -12,6 +12,8 @@ enum {
 	MAP_PRIVATE	= 0x2,
 	MAP_FIXED	= 0x10,
 
+	MADV_FREE	= 0x6,
+
 	SA_SIGINFO	= 0x40,
 	SA_RESTART	= 0x2,
 	SA_ONSTACK	= 0x1,

これらのCヘッダファイルでは、MADV_FREEマクロが0x6として定義されています。これはNetBSDシステムにおけるMADV_FREEの実際の値です。GoのC.MADV_FREEはこの値を参照します。

src/pkg/runtime/mem_netbsd.c

@@ -28,9 +28,7 @@ runtime·SysAlloc(uintptr n)
 void
 runtime·SysUnused(void *v, uintptr n)
 {
-\tUSED(v);\n-\tUSED(n);\n-\t// TODO(rsc): call madvise MADV_DONTNEED
+\truntime·madvise(v, n, MADV_FREE);
 }
 
 void

runtime·SysUnused関数の実装が変更されました。以前のダミーコードとTODOコメントが削除され、代わりにruntime·madvise(v, n, MADV_FREE);が呼び出されています。これは、Goランタイムが指定されたメモリ領域vとサイズnを、MADV_FREEアドバイスを使ってOSに解放するよう通知することを意味します。

src/pkg/runtime/sys_netbsd_386.s (32ビット版)

@@ -83,6 +83,13 @@ TEXT runtime·munmap(SB),7,$-4
 	MOVL	$0xf1, 0xf1		// crash
 	RET
 
+TEXT runtime·madvise(SB),7,$-4
+\tMOVL	$75, AX			// sys_madvise
+\tINT	$0x80
+\tJAE	2(PC)
+\tMOVL	$0xf1, 0xf1		// crash
+\tRET
+
 TEXT runtime·setitimer(SB),7,$-4
 	MOVL	$425, AX		// sys_setitimer
 	INT	$0x80

このアセンブリコードは、runtime·madviseという新しい関数を定義しています。

  • MOVL $75, AX: NetBSDのmadviseシステムコール番号である75AXレジスタに設定します。
  • INT $0x80: システムコールを実行するための割り込みを発生させます。
  • JAE 2(PC): システムコールが成功した場合(キャリーフラグがクリアされている場合)、次の命令(クラッシュ命令)をスキップします。
  • MOVL $0xf1, 0xf1: システムコールが失敗した場合に、意図的にクラッシュさせるための命令です。

src/pkg/runtime/sys_netbsd_amd64.s (64ビット版)

@@ -10,7 +10,6 @@
 
 // int32 lwp_create(void *context, uintptr flags, void *lwpid)
 TEXT runtime·lwp_create(SB),7,$0
-\n \tMOVQ\tcontext+0(FP), DI
 \tMOVQ\tflags+8(FP), SI
 \tMOVQ\tlwpid+16(FP), DX
 @@ -248,6 +247,17 @@ TEXT runtime·munmap(SB),7,$0
 	MOVL	$0xf1, 0xf1		// crash
 	RET
 
+\n+TEXT runtime·madvise(SB),7,$0
+\tMOVQ	addr+0(FP), DI		// arg 1 - addr
+\tMOVQ	len+8(FP), SI		// arg 2 - len
+\tMOVQ	behav+16(FP), DX	// arg 3 - behav
+\tMOVQ	$75, AX			// sys_madvise
+\tSYSCALL
+\tJCC	2(PC)
+\tMOVL	$0xf1, 0xf1		// crash
+\tRET
+\n TEXT runtime·sigaltstack(SB),7,$-8
 \tMOVQ\tnew+8(SP), DI		// arg 1 - nss
 \tMOVQ\told+16(SP), SI		// arg 2 - oss

このアセンブリコードもruntime·madvise関数を定義していますが、64ビットアーキテクチャ向けです。

  • MOVQ addr+0(FP), DIMOVQ len+8(FP), SIMOVQ behav+16(FP), DX: 関数呼び出し規約に従って、引数(アドレス、長さ、振る舞い)をレジスタにロードします。
  • MOVQ $75, AX: NetBSDのmadviseシステムコール番号である75AXレジスタに設定します。
  • SYSCALL: システムコールを実行します。
  • JCC 2(PC): システムコールが成功した場合(キャリーフラグがクリアされている場合)、次の命令(クラッシュ命令)をスキップします。
  • MOVL $0xf1, 0xf1: システムコールが失敗した場合に、意図的にクラッシュさせるための命令です。

これらの変更により、GoランタイムはNetBSD上で不要なメモリをOSに効率的に通知し、OSがそのメモリを再利用できるようにすることで、メモリフットプリントの削減とパフォーマンスの向上に貢献します。

関連リンク

参考にした情報源リンク