[インデックス 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_DONTNEED
とMADV_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_DONTNEED
やMADV_FREE
といったフラグと共に使用して、OSに物理ページを再利用できることを伝えます。ただし、これは物理メモリの即時解放を保証するものではなく、OSがいつこれらのページを実際に再利用するかはOSの判断に委ねられます。
技術的詳細
このコミットの主要な変更点は、NetBSDにおけるGoランタイムのメモリ管理、特にruntime.SysUnused
関数の動作を改善することにあります。
-
MADV_FREE
定数の追加:src/pkg/runtime/defs_netbsd.go
、src/pkg/runtime/defs_netbsd_386.h
、src/pkg/runtime/defs_netbsd_amd64.h
の各ファイルに、MADV_FREE
定数が追加されました。これは、madvise
システムコールで使用するMADV_FREE
アドバイスの値をGoランタイムが認識できるようにするためです。NetBSDではMADV_FREE
の値は0x6
です。
-
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に効率的に通知できるようになります。
-
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
:第一引数addr
をDI
レジスタにロードします。MOVQ len+8(FP), SI
:第二引数len
をSI
レジスタにロードします。MOVQ behav+16(FP), DX
:第三引数behav
をDX
レジスタにロードします。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
システムコール番号である75
をAX
レジスタに設定します。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), DI
、MOVQ len+8(FP), SI
、MOVQ behav+16(FP), DX
: 関数呼び出し規約に従って、引数(アドレス、長さ、振る舞い)をレジスタにロードします。MOVQ $75, AX
: NetBSDのmadvise
システムコール番号である75
をAX
レジスタに設定します。SYSCALL
: システムコールを実行します。JCC 2(PC)
: システムコールが成功した場合(キャリーフラグがクリアされている場合)、次の命令(クラッシュ命令)をスキップします。MOVL $0xf1, 0xf1
: システムコールが失敗した場合に、意図的にクラッシュさせるための命令です。
これらの変更により、GoランタイムはNetBSD上で不要なメモリをOSに効率的に通知し、OSがそのメモリを再利用できるようにすることで、メモリフットプリントの削減とパフォーマンスの向上に貢献します。
関連リンク
参考にした情報源リンク
- NetBSD
madvise()
man page: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGUNeqAFAAgx3gpBL-rrD0wlA3j-ZmJUPBjmoYTCmJ1-wvIgMjYepYI50AUBz4fCg_Iwd4otEt5mFVFAaBqwmrlKy7l986hEsUEDS755k1Iop0JseYy066VkonW - LWN.net -
MADV_FREE
vsMADV_DONTNEED
: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGFwxfh1qE5Nliza2cUxUOZR-JkIyO5t5l_TNFmMQP1S89Ffk4CtBrjrB0sE4cQKOSNZRa4PHBzorJfU8kTxBbUoQTCIdE0qB5N9THUhVD5n5n8mDfCchn2pFDq - Go runtime
SysUnused
discussion: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGBbKfUniofPpu9mh6hyDhZuwe-GZo2lv70Ids4x60X6dgPSRpr80uhD2ALhsdlgMH-Vnmi24wDjQ7VmHY3imnPNv-EOKfULSlpmNuJYGo9tvXd7OH0BS7ketesUcEX1g3tPOdghJ-wu43r2C7YF68= - Go
madvise
system call in runtime: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEQwM7KMg1Mqp54ib0VgVMEB3H3OWF3KMUSnk9S094mj7v1gBm6k1HeacXlvCyCNifLmB8ND2US10E6hGWK3EU855mwu57fsL7VLkxKbqU4OunLJ6L5ShLFvm0w