Ruby 3.0 リファレンスマニュアル
> ライブラリ一覧
> 組み込みライブラリ
> GCモジュール
module GC
クラス・モジュールの継承リスト: GC
要約
GC は Ruby インタプリタの「ゴミ集め(Garbage Collection)」を制御するモジュールです。
GCのチューニングについて
Ruby 2.1ではRGenGCと呼ばれる新たなGCメカニズムが導入されました。それにともない、以下の環境変数が導入され、これらを設定することでGCの動作をチューニングすることができます。これらの環境変数の効果はRubyの起動時のみ有効です(つまりrubyを動かしている途中で変更することはできません)。
チューニングのための環境変数
- RUBY_GC_HEAP_INIT_SLOTS (default: 10000) - 最初に確保されるスロット数。
- RUBY_GC_HEAP_FREE_SLOTS (default: 4096) - GC後、必ずこの数の空きスロット数が確保される。
つまりGC後に空きスロットが足りなければ新たなページを確保し、空きスロット数を増やす。
- RUBY_GC_HEAP_GROWTH_FACTOR (default: 1.8) - Rubyではスロットを増やすための
メモリ確保をするたびに確保するサイズをこの係数で大きくする。
つまり全スロット数は指数的に増大する。これは動かしているRubyプログラムが
必要とするスロット数に速やかに到達するための仕組みである。
- RUBY_GC_HEAP_GROWTH_MAX_SLOTS (default: 0) -
RUBY_GC_HEAP_GROWTH_FACTORで説明したようにRubyではスロットのためのメモリ確保のサイズを
指数的に大きくしていくが、その上限を決める値。0は上限なしを意味する。
この値を指定すると、スロット数が特定の値を越えると指数的ではなく線形的に
スロット数が増大する。
- RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO (2.4以降、default: 0.20) -
GC後の空きスロット割合の下限。
つまり空きスロット数の全スロット数に対する割合がこの値より小さいときは新たな
ページを確保する。
- RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO (2.4以降、
default: 0.40) - GC後の空きスロットの割合の目標。
RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIOの閾値にひっかかって新たなスロットを確保するときは
この割合が目標となる。
この値が 0.0 の場合は、RUBY_GC_HEAP_GROWTH_FACTORを直接使う。
- RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO (2.4以降、default: 0.65) -
GC後の空きスロットの割合の上限。
空きスロット数の全スロット数に対する割合がこの値より大きい場合は
積極的にページを解放する。
- RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR (2.0) - RubyのフルGCを呼びだすための oldobject
数の上限を決めるための係数。
RubyのフルGCは oldobject の個数が閾値 old_objects_limit
を越えるごとに実行される。old_objects_limit はフルGCの直後に変更される。
その値はフルGC直後のの oldobject の個数 (
old_objects) の RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR 倍となる。
つまり、フルGC直後から oldobject の個数が RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR 倍に
なったタイミングでフルGCが実行される。
この値を調整することでフルGCの頻度を調整できる。
- RUBY_GC_MALLOC_LIMIT (default: 16*1024*1024 = 16MB) - malloc によるマイナーGC発動の
閾値の初期値
- RUBY_GC_MALLOC_LIMIT_MAX (default: 32*1024*1024 = 32MB) - malloc によるマイナーGC発動の
閾値の最大値
- RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR (default: 1.4) - malloc によるマイナーGC発動の
閾値の増加率
- RUBY_GC_OLDMALLOC_LIMIT (default: 16*1024*1024 = 16MB) - oldobject による malloc
によるフルGC発動の閾値の初期値
- RUBY_GC_OLDMALLOC_LIMIT_MAX (default: 128*1024*1024 = 128MB) oldobject による malloc
によるフルGC発動の閾値の最大値
- RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR (default: 1.2) - oldobject による malloc
によるフルGC発動の閾値の増加率
以下の2つの環境変数はobsoleteであり、新しいものを使うことが望ましい
- RUBY_FREE_MIN -> RUBY_GC_HEAP_FREE_SLOTS
- RUBY_HEAP_MIN_SLOTS -> RUBY_GC_HEAP_INIT_SLOTS
RUBY_GC_HEAP_GROWTH_FACTOR と RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO に関する補足説明
RUBY_GC_HEAP_GROWTH_FACTOR と RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO はともに
GC後に空きスロットが少ないときにどれだけの量のメモリを新たに確保するかを決めるパラメータである。この2つのパラメータの優先順位は以下の通りである。
- RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO が 0.0 のときはこの値は無視され、
RUBY_GC_HEAP_GROWTH_FACTOR のみが利用される。つまり
スロットが不足状態の場合にはスロット数は単純に指数的に増加する。
- RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO が 0.0 でない場合には、
RUBY_GC_HEAP_GROWTH_FACTOR で決まるスロット数と
RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO で決まるスロット数の大きいほうが採用される。
当然、RUBY_GC_HEAP_GROWTH_MAX_SLOTS はこれらより優先度が高いことに注意。
malloc閾値についての説明
Rubyが利用するメモリはスロット以外にもある。例えば長い文字列は malloc によってCのヒープ上に確保される。GCはこのようなヒープ上のメモリを解放するためにも実行される。そこで、rubyでは malloc によるメモリ消費量を保持し、この消費量がある閾値を越えるとGCが起動される。また、GCが起動されるごとにこの消費量カウンタが0にリセットされる。
このカウンタは2種類あり、一方は malloc_increase_bytes、もう一方は
oldmalloc_increase_bytes と呼ばれる。この2つの性質は以下のようになっている。
- malloc_increase_bytes について
- malloc_increase_bytes はRuby内でのmalloc, realloc, freeの呼びだし
(ruby_xmalloc, ruby_xrealloc, ruby_xfreeなど)によるメモリ利用量の増減を
計測する
- malloc_increase_bytes はマイナーGCで0にリセットされる
- malloc_increase_bytes が malloc_increase_bytes_limits を越えるとマイナーGCが起動される
- malloc_increase_bytes_limits は処理系の起動時に RUBY_GC_MALLOC_LIMIT で初期化される
- malloc_increase_bytes_limits を越えたことが原因でGCが起動された場合は
malloc_increase_bytes_limits が RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR 倍される
(ただし、 RUBY_GC_MALLOC_LIMIT_MAX を越えることはできない)
- oldmalloc_increase_bytes について
- oldmalloc_increase_bytes はRuby内でのmalloc, realloc, freeの呼びだし
(ruby_xmalloc, ruby_xrealloc, ruby_xfreeなど)によるメモリ利用量の増減を
計測する(これは malloc_increase_bytes と同じ)
- oldmalloc_increase_bytes はフルGCで0にリセットされる
- oldmalloc_increase_bytes が
oldmalloc_increase_bytes_limits を越えるとフルGCが起動される
- oldmalloc_increase_bytes_limits は処理系の起動時に
RUBY_GC_OLDMALLOC_LIMIT で初期化される
- oldmalloc_increase_bytes_limits を越えたことが原因でGCが起動された場合は
oldmalloc_increase_bytes_limits が RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR 倍される
(ただし、 RUBY_GC_OLDMALLOC_LIMIT_MAX を越えることはできない)
実行中のパラメータ
プログラム実行中には、GCに関する統計情報/閾値情報を GC.stat で見ることができるが、この文章で説明した以下の情報はこれで調べることができる。
- malloc_increase_bytes
- malloc_increase_bytes_limits
- oldmalloc_increase_bytes
- oldmalloc_increase_bytes_limits
- old_objects_limit
チューニングについて
- 原理的にはメモリ使用量と実行速度のトレードオフがある。
実行速度を上げるためにはGCの回数を減らせばよいが、そうすると
メモリ使用量は増える傾向になる。
- チューニングのためにはまず計測することが重要。GC.stat、GC::Profilerなどを
利用してGCを計測する
- GCが性能上のボトルネックではないことも多い。そういう部分も含め計測する。
- newrelicのような高度なツールを使うことも考慮する
- http://tmm1.net/ruby21-rgengc/ には
RUBY_GC_HEAP_INIT_SLOTS や RUBY_GC_HEAP_FREE_SLOTS
のチューニングに関する簡単な指針が書いてあって参考になる
- 結局の所トライ&エラーで調整する必要がある。
この設定を理解するための用語集
- スロット - Ruby のオブジェクトを1つ保持するためのメモリ領域。
実際にはこの領域からのポインタがCのヒープ領域に確保したメモリを所持していることが多く、
メモリ上の実占有領域はスロット外にもあることがしばしばある。
RubyのGCのチューニングには重要な概念。
- RGenGC - Ruby2.1で採用された世代別GC。マイナーGCとフルGCの2段階のGCをすることで
効率的なGCを実現する。
- マイナーGC - 新しいオブジェクト(前回のGCの後に生成されたオブジェクト)
のみを対象としたGC。GCすべきオブジェクトの数が少ないので高速。
また、多くのオブジェクトは経験的に生成されてすぐ不要になるので
マイナーGCは効率的に動作する可能性が高い。
マイナーGCでGCされなかったオブジェクトはoldobjectと呼ぶ。
- フルGC (メジャーGC) - すべてのオブジェクトを対象としたGC。マイナーGCより遅いため、
フルGCの回数を減らすことはGC性能に重要な問題である。
- ページ - スロットのメモリ確保は効率性のため、
「すべて別々に確保する」「大きなメモリの塊で一気に確保する」
のどちらでもなく、ページと呼ばれる単位で数百個という単位で確保される。
x86_64上でのlinuxでは16kバイトがページのサイズと決められている。
スロット用のメモリの確保および解放はこの単位で行われる。
この「ページ」はOSのメモリ管理用語であるページとは異なる概念であることに注意。
参考資料
@see ObjectSpace
特異メソッド
インスタンスメソッド
定数