要約
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
目次
- 特異メソッド
- インスタンスメソッド
- 定数
特異メソッド
count -> Integer
[permalink][rdoc][edit]-
プロセス開始からガーベージコレクトを実行した回数を Integer で返します。
GC.count # => 3
disable -> bool
[permalink][rdoc][edit]-
ガーベージコレクトを禁止します。
前回の禁止状態を返します(禁止されていたなら true, GC が有効であったなら、 false)。
GC.disable # => false GC.disable # => true
[SEE_ALSO] GC.enable
enable -> bool
[permalink][rdoc][edit]-
ガーベージコレクトを許可します。
前回の禁止状態を返します(禁止されていたなら true, GC が有効であったなら、 false)。
[SEE_ALSO] GC.disable
GC.disable # => false GC.enable # => true GC.enable # => false
latest_gc_info(result_hash = {}) -> Hash
[permalink][rdoc][edit]latest_gc_info(key) -> object
-
最新のGCの情報を返します。
- [PARAM] result_hash:
- 戻り値のためのハッシュを指定します。省略した場合は新しくハッシュを作成します。result_hash の内容は上書きされます。
- [PARAM] key:
- 得られる情報から特定の情報を取得したい場合にキーを Symbol で指定します。
latest = GC.latest_gc_info latest # => {:major_by=>nil, :gc_by=>:newobj, :have_finalizer=>false, :immediate_sweep=>false, :state=>:sweeping} stat = GC.stat merged = GC.latest_gc_info(stat) merged == latest.merge(stat) # => true GC.latest_gc_info(:gc_by) # => :newobj
start(full_mark: true, immediate_sweep: true) -> nil
[permalink][rdoc][edit]-
ガーベージコレクトを開始します。
GC#garbage_collect や ObjectSpace.#garbage_collect と同じ働きをします。 GC.disable により GC が禁止されている場合でもガベージコレクトを開始します。
nil を返します。
- [PARAM] full_mark:
- マイナー GC を動作させる場合は false を、そうでない場合は true を指定します。
- [PARAM] immediate_sweep:
- sweep を遅らせる(Lazy Sweep を行う)場合は false を、そうでない場合は true を指定します。
注意: これらのキーワード引数は Ruby の実装やバージョンによって異なります。将来のバージョンとの互換性も保証されません。また、Ruby の実装がサポートしていない場合はキーワード引数を指定しても無視される可能性があります。
GC.count # => 3 GC.start # => nil GC.count # => 4
stat(result_hash = {}) -> {Symbol => Integer}
[permalink][rdoc][edit]stat(key) -> Numeric
-
GC 内部の統計情報を Hash で返します。
- [PARAM] result_hash:
- 戻り値のためのハッシュを指定します。省略した場合は新しくハッシュを作成します。result_hash の内容は上書きされます。
- [PARAM] key:
- 得られる統計情報から特定の情報を取得したい場合にキーを Symbol で指定します。
- [RETURN]
- GC 内部の統計情報をHash で返します。引数 key を指定した場合は数値を返します。
GC.stat # => { :count=>0, :heap_allocated_pages=>24, :heap_sorted_length=>24, :heap_allocatable_pages=>0, :heap_available_slots=>9783, :heap_live_slots=>7713, :heap_free_slots=>2070, :heap_final_slots=>0, :heap_marked_slots=>0, :heap_swept_slots=>0, :heap_eden_pages=>24, :heap_tomb_pages=>0, :total_allocated_pages=>24, :total_freed_pages=>0, :total_allocated_objects=>7796, :total_freed_objects=>83, :malloc_increase_bytes=>2389312, :malloc_increase_bytes_limit=>16777216, :minor_gc_count=>0, :major_gc_count=>0, :remembered_wb_unprotected_objects=>0, :remembered_wb_unprotected_objects_limit=>0, :old_objects=>0, :old_objects_limit=>0, :oldmalloc_increase_bytes=>2389760, :oldmalloc_increase_bytes_limit=>16777216 }
戻り値のハッシュは処理系に依存します。これは将来変更になるかもしれません。
本メソッドは C Ruby 以外では動作しません。
stress -> bool
[permalink][rdoc][edit]-
GCがストレスモードかどうかを返します。
真が設定されている場合は GC を行えるすべての機会に GC を行います。
[SEE_ALSO] GC.stress=
stress=(value)
[permalink][rdoc][edit]-
GCのストレスモードを引数 value に設定します。引数 value が真に設定されている間は、GC を行えるすべての機会に GC を行います。
この機能はデバッグ用途に提供されています。ストレスモードを有効にするとプログラムのパフォーマンスが低下します。
- [PARAM] value:
- 任意のオブジェクト。整数以外の値を指定した場合は真偽値として解釈されます。整数を指定する場合は以下のフラグをOR演算した値を指定します。
- 0x01
-
マイナー GC を動作させる場合に指定します。
- 0x02
-
sweep を遅らせる(Lazy Sweep を行う)に指定します。
- 0x04
-
malloc/calloc/realloc の後でメジャーGCを動作させる場合に指定します。
GC.stress # => false GC.stress = true GC.stress # => true
[SEE_ALSO] GC.stress
インスタンスメソッド
garbage_collect(full_mark: true, immediate_sweep: true) -> nil
[permalink][rdoc][edit]-
ガーベージコレクトを開始します。
GC.start や ObjectSpace.#garbage_collect と同じ働きをします。 GC.disable により GC が禁止されている場合でもガベージコレクトを開始します。
nil を返します。
- [PARAM] full_mark:
- マイナー GC を動作させる場合は false を、そうでない場合は true を指定します。
- [PARAM] immediate_sweep:
- sweep を遅らせる(Lazy Sweep を行う)場合は false を、そうでない場合は true を指定します。
注意: これらのキーワード引数は Ruby の実装やバージョンによって異なります。将来のバージョンとの互換性も保証されません。また、Ruby の実装がサポートしていない場合はキーワード引数を指定しても無視される可能性があります。
include GC GC.count # => 3 garbage_collect GC.count # => 4
定数
INTERNAL_CONSTANTS -> {Symbol => Integer}
[permalink][rdoc][edit]-
GC用内部定数の値を保持するハッシュテーブルです。
GC::INTERNAL_CONSTANTS # => {:RVALUE_SIZE=>40, :HEAP_PAGE_OBJ_LIMIT=>408, :HEAP_PAGE_BITMAP_SIZE=>56, :HEAP_PAGE_BITMAP_PLANES=>4}
OPTS -> [String]
[permalink][rdoc][edit]-
コンパイル時に指定したGCのオプションです。
可能性があるオプション文字列は以下の通りです。
- "GC_DEBUG"
- "USE_RGENGC"
- "RGENGC_DEBUG"
- "RGENGC_CHECK_MODE"
- "RGENGC_PROFILE"
- "RGENGC_ESTIMATE_OLDMALLOC"
- "GC_PROFILE_MORE_DETAIL"
- "GC_ENABLE_LAZY_SWEEP"
- "CALC_EXACT_MALLOC_SIZE"
- "MALLOC_ALLOCATED_SIZE"
- "MALLOC_ALLOCATED_SIZE_CHECK"
- "GC_PROFILE_DETAIL_MEMORY"
例:
GC::OPTS # => ["USE_RGENGC", "RGENGC_ESTIMATE_OLDMALLOC", "GC_ENABLE_LAZY_SWEEP"] # この場合、GCデバッグ機能やプロファイル機能は無効化されている