9

この記事は最終更新日から3年以上が経過しています。

投稿日

更新日

Nim's Garbage Collectorを日本語訳してみた

相変わらずGoogle翻訳頼りです。
作業リポジトリ:https://github.com/tauplus/nim_doc_ja/blob/master/gc_ja.md

Nimのガベージコレクター

原著:Andreas Rumpf

原文:https://nim-lang.org/docs/gc.html

Version:1.0.4

「地獄への道は善意で舗装されています。」

イントロダクション(Introduction)

このドキュメントでは、GCの仕組みと(ソフト)リアルタイムシステム用にGCを調整する方法について説明します。

基本的なアルゴリズムは、サイクル検出による遅延参照カウントです。
スタック上の参照は、パフォーマンスの向上(およびCコード生成の容易化)のためにカウントされません。
現在、サイクル検出は単純なマーク&スイープGCによって実行されます。これは全て(スレッドローカルヒープ)をスキャンする必要があります。
--gc:v2は、これをインクリメンタルマーク&スイープに置き換えます。ただし、まだ正式版の準備ができていません。

GCは、メモリ割り当て操作でのみトリガーされます。タイマーによってはトリガーされず、バックグラウンドスレッドでは実行されません。

完全なコレクションを強制するにはGC_fullCollectを呼び出します。一般に、GCに処理を行わせ、完全なコレクションを強制しない方が良いことに注意してください。

サイクルコレクター(Cycle collector)

サイクルコレクターは、GC_enableMarkAndSweepおよびGC_disableMarkAndSweepを使用して、GCの他の部分から独立して有効化/無効化できます。

リアルタイムサポート(Realtime support)

リアルタイムサポートを有効にするには、シンボルuseRealtimeGCを--define:useRealtimeGCで定義する必要があります(これをconfigファイルに追加することもできます)。
このスイッチを使用すると、GCは次の操作をサポートします。

proc GC_setMaxPause*(maxPauseInUs: int)
proc GC_step*(us: int, strongAdvice = false, stackSize = -1)

パラメーターmaxPauseInUsおよびusの単位はマイクロ秒です。

これらの2つのプロシージャは、リアルタイムGCの2つの運用法です。

(1) GC_SetMaxPause Mode

プログラムの起動時にGC_SetMaxPauseを呼び出すと、トリガーされた各GCの実行がmaxPause時間より長くかからないようにします。
ただし、newを呼び出すたびにGCがトリガーされ、maxPause時間がかかるため 、作業が均等に分散されない可能性があります(そして一般的にそうなります)。

(2) GC_step Mode

これにより、GCに最大usマイクロ秒の間、処理を実行させることができます。
これは、メインループでGCを呼び出して、機能することを確認するのに役立ちます。
すべてのGCアクティビティをGC_step呼び出しにバインドするには、プログラムの起動時にGC_disableでGCを非アクティブ化します。
strongAdvicetrueに設定されている場合、GCは収集サイクルの実行を強制されます。
そうしないと、収集するガベージがあまりない場合、GCは何もしないことを決定する場合があります。
stackSizeパラメーターを使用して、現在のスタックサイズを指定することもできます。
スタック上の特定のポイントより下にユニークなNim参照がないことがわかっている場合、パフォーマンスを改善できます。
指定するサイズが、潜在的に最悪なケースのサイズよりも大きいことを確認してください。

これらのプロシージャは、「ベストエフォート」のリアルタイム保証を提供します。
特に、サイクルコレクターはまだ期限を認識していません。
これを無効にすると、より予測可能なリアルタイムの動作が得られます。
テストでは、最新のCPU(サイクルコレクターを無効にした場合)のほとんどすべてのケースで2msの最大休止時間が満たされることが示されています。

時間測定(Time measurement)

GCの時間測定方法(実装についてはlib/system/timers.nimを参照):

  • WindowsのQueryPerformanceCounterおよびQueryPerformanceFrequency
  • Mac OS Xのmach_absolute_time
  • Posixシステムのgettimeofday

そのため、内部でナノ秒の解像度をサポートしています。
ただし、便宜上、APIはマイクロ秒を使用します。

シンボルreportMissedDeadlinesを定義して、期限に間に合わなかった場合にGC出力を作成します。
コレクターの以降のバージョンでは、APIによってレポート機能が強化されサポートされます。

GCの調整(Tweaking the GC)

コレクターは、workPackage番目の反復ごとに作業にまだ時間が残っているかどうかをチェックします。
これは現在100に設定されています。つまり、再確認する前に最大100個のオブジェクトがトラバースされて解放されます。
したがって、workPackageはタイミングの粒度に影響し、高度に特殊化された環境や古いハードウェアでは調整する必要がある場合があります。

メモリの追跡(Keeping track of memory)

Nimによって割り当てられたメモリをCに渡す必要がある場合は、プロシージャGC_refおよびGC_unrefを使用してオブジェクトを参照済みとしてマークし、GCによって解放されないようにすることができます。
メモリを追跡するために使用できるsystemの他の便利なプロシージャは次のとおりです。

  • getTotalMem() :GCによって管理されている合計メモリの量を返します。
  • getOccupiedMem() :GCによって予約され、オブジェクトによって使用されるバイト数。
  • getFreeMem() :GCによって予約され、使用されていないバイト。

これらの数値は通常ヒープ全体ではなく、実行中のスレッド専用です。
ただし、--gc:boehmおよび--gc:goは例外です。

GC_refおよびGC_unrefに加えて、alloc,allocShared,またはallocCStringArrayなどのプロシージャを使用してメモリを手動で割り当てることにより、GCを回避できます。
GCはそれらを解放しようとしません。それらの処理が完了したら、それぞれのdeallocペアを呼び出す必要があります。そうしないと、リークが発生します。

ヒープダンプ(Heap dump)

ヒープダンプ機能はまだ初期段階にありますが、既に有用であることが証明されているので、役に立つかもしれません。
ヒープダンプを取得するには、-d:nimTypeNamesを指定してコンパイルし、プログラムの戦略的な場所でdumpNumberOfInstancesを呼び出します。
これにより、プログラムで使用される型のリストが作成され、すべての型について、その型のオブジェクトインスタンスの合計量と、これらのインスタンスが占有するバイトの合計量が生成されます。
このリストは現在ソートされていません!ソートするには、外部シェルスクリプトハッキングを使用する必要があります。

数値は、すべてのGCヒープ内のオブジェクトの数をカウントし、現在のスレッドだけでなく、実行中のすべてのスレッドを参照します。
(現在のスレッドはdumpNumberOfInstancesを呼び出すスレッドになります。)これは後のバージョンで変更される可能性があります。

ガベージコレクターオプション(Garbage collector options)

ソースコードのコンパイル時に使用するガベージコレクタを選択できます。
選択したガベージコレクタのコンパイルコマンドで--gc:を渡すことができます。

同じNimコードをコンパイルして、任意のガベージコレクターを使用できます。
通常、Nim構文は、ガベージコレクターごとに変更されません。
JavaScriptおよびNodeJSコンパイルターゲットにはガベージコレクターは使用されません。
NimScriptターゲットはNim VMガベージコレクターを使用します。

Nimを初めて使用し、始めたばかりの場合、デフォルトのガベージコレクタは、ほとんどの一般的なユースケースに適合するようにバランスが取られています。

新規登録して、もっと便利にQiitaを使ってみよう

  1. あなたにマッチした記事をお届けします
  2. 便利な情報をあとで効率的に読み返せます
ログインすると使える機能について

コメント

この記事にコメントはありません。
あなたもコメントしてみませんか :)
新規登録
すでにアカウントを持っている方はログイン
9