決定論的とは、航空宇宙飛行ソフトウェアのような重要なリアルタイム ソフトウェアで使用できることを漠然と意味しています。ガベージ コレクター (および動的メモリ割り当て) は、非決定論的と見なされるため、飛行中のソフトウェアでは絶対にダメです。ただし、これについては進行中の研究があることを知っているので、この問題はまだ解決されているのでしょうか。
また、使用方法を制限するガベージ コレクション アルゴリズムも質問に含めています。
決定論的とは、航空宇宙飛行ソフトウェアのような重要なリアルタイム ソフトウェアで使用できることを漠然と意味しています。ガベージ コレクター (および動的メモリ割り当て) は、非決定論的と見なされるため、飛行中のソフトウェアでは絶対にダメです。ただし、これについては進行中の研究があることを知っているので、この問題はまだ解決されているのでしょうか。
また、使用方法を制限するガベージ コレクション アルゴリズムも質問に含めています。
この返信に対して多くの反対票が投じられる可能性があることはわかっていますが、そもそも動的メモリを回避しようとしているのなら、それはノーノーだと言ったので、なぜ GC を使用するのですか? 予測可能なランタイム速度が主な関心事であるリアルタイム システムで GC を使用することはありません。可能な限り動的メモリを避けるため、動的オブジェクトは非常に少なく、手動で動的割り当てを処理するので、何かがいつ解放され、どこにあるかを 100% 制御できます。リリースされました。結局、GC が決定論的ではないだけでなく、free() は malloc() ほど決定論的ではありません。free() 呼び出しでメモリを空きとしてマークする必要があるとは誰も言いません。解放されたメモリブロックを囲む小さな空きメモリブロックを大きなメモリブロックに結合しようとする可能性がありますが、この動作は決定論的ではありません。
クリティカルなリアルタイム システムでは、システム標準の malloc()/free() を別の実装に置き換えたり、独自の実装を作成したりすることさえあるかもしれません (思ったほど難しくはありません! 楽しみのために以前にそれを行ったことがあります)。それの) 最も決定論的に動作します。私にとって GC は単純に便利なものです。これは、プログラマーが洗練された malloc()/free() の計画に集中することから解放され、代わりにシステムがこれを自動的に処理するようにするためのものです。迅速なソフトウェア開発を行うのに役立ち、メモリ リークを見つけて修正するデバッグ作業の時間を節約できます。しかし、オペレーティング システム カーネル内で GC を使用しないのと同じように、重要なリアルタイム アプリケーション内でも GC を使用しません。
より洗練されたメモリ処理が必要な場合は、必要に応じて (そして最も決定論的に) 機能する独自の malloc()/free() を作成し、その上に独自の参照カウント モデルを作成します。参照カウントは依然として手動のメモリ管理ですが、単に malloc()/free() を使用するよりもはるかに快適です。超高速ではありませんが、決定論的 (少なくとも ref カウンターの増加/減少は速度が決定論的です) であり、循環参照がない限り、アプリケーション全体で保持/解放戦略に従うと、すべてのデッド メモリがキャッチされます。唯一の非決定論的な部分は、 release の呼び出しが ref カウンターを減少させるだけなのか、それとも実際にオブジェクトを解放するのか (ref カウントがゼロになるかどうかによって異なります) がわからないということですが、 「releaseWithoutFreeing」と言う関数 、これにより ref カウンターが 1 つ減少しますが、ゼロに達したとしても、オブジェクトはまだ free() されません。malloc()/free() の実装には、保持カウンターがゼロで、まだ解放されていないすべてのオブジェクトを検索して解放する関数「findDeadObjects」を含めることができます (後で、重要度が低い場合)。そのような種類のタスクにより多くの時間を割くコードの一部)。これも決定論的ではないため、「findDeadObjectsForUpTo(ms)」のように、これに使用される時間を制限できます。ms は、それらを見つけて解放するために使用できるミリ秒の量であり、今回はすぐに戻ってきます。量子が使用されているため、このタスクにあまり時間をかけません。malloc()/free() の実装には、保持カウンターがゼロで、まだ解放されていないすべてのオブジェクトを検索して解放する関数「findDeadObjects」を含めることができます (後で、重要度が低い場合)。そのような種類のタスクにより多くの時間を割くコードの一部)。これも決定論的ではないため、「findDeadObjectsForUpTo(ms)」のように、これに使用できる時間を制限できます。ms は、それらを見つけて解放するために使用できるミリ秒の量であり、今回はすぐに戻ってきます。量子が使用されているため、このタスクにあまり時間をかけません。malloc()/free() の実装には、保持カウンターがゼロで、まだ解放されていないすべてのオブジェクトを検索して解放する関数「findDeadObjects」を含めることができます (後で、重要度が低い場合)。そのような種類のタスクにより多くの時間を割くコードの一部)。これも決定論的ではないため、「findDeadObjectsForUpTo(ms)」のように、これに使用できる時間を制限できます。ms は、それらを見つけて解放するために使用できるミリ秒の量であり、今回はすぐに戻ってきます。量子が使用されているため、このタスクにあまり時間をかけません。そのような種類のタスクにより多くの時間を割けるコードの重要度の低い部分にいる場合)。これも決定論的ではないため、「findDeadObjectsForUpTo(ms)」のように、これに使用できる時間を制限できます。ms は、それらを見つけて解放するために使用できるミリ秒の量であり、今回はすぐに戻ってきます。量子が使用されているため、このタスクにあまり時間をかけません。そのような種類のタスクにより多くの時間を割けるコードの重要度の低い部分にいる場合)。これも決定論的ではないため、「findDeadObjectsForUpTo(ms)」のように、これに使用される時間を制限できます。ms は、それらを見つけて解放するために使用できるミリ秒の量であり、今回はすぐに戻ってきます。量子が使用されているため、このタスクにあまり時間をかけません。
Metronome GCとBEA JRockitは、私が認識している 2 つの決定論的 GC 実装です (どちらも Java 用)。
たまたまスタック オーバーフローを検索していて、このかなり古い投稿に気付きました。
Jon Anderson さんが JamaicaVM について言及しました。これらの投稿は 4 年以上前から行われているため、ここに投稿された情報のいくつかに応答することが重要だと思います。
私は、JamaicaVM、JamaicaCAR、および Veriflux の開発者およびマーケティング担当者である aicas で働いています。
JamaicaVM にはハード リアルタイム ガベージ コレクタがあります。完全先制です。リアルタイム オペレーティング システムで必要とされる動作とまったく同じです。プリエンプションの待ち時間は CPU 速度に依存しますが、Ghz クラスのプロセッサでは、ガベージ コレクターのプリエンプションが 1 マイクロ秒未満であると仮定します。プロセス アドレス空間ごとに最大 3 GB のメモリをサポートする 32 ビット シングルコア バージョンがあります。プロセス アドレス空間ごとに 3 GB のメモリと複数のコアをサポートする 32 ビット マルチコア バージョンがあります。プロセス アドレス空間あたり最大 128 GB のメモリをサポートする 64 ビットのシングルコア バージョンとマルチコア バージョンもあります。ガベージ コレクターのパフォーマンスは、メモリのサイズとは無関係です。GC を完全にメモリ不足で実行することに関する応答の 1 つに対応して、ハードリアルタイムシステムの場合、それを行うようにプログラムを設計することはありません。実際、このシナリオではハード リアルタイム GC を使用できますが、アプリケーションにとっておそらく受け入れられない最悪の場合の実行時間を考慮する必要があります。
代わりに、正しい方法は、プログラムを分析して最大のメモリ割り当てを確認し、ハード リアルタイム ガベージ コレクタを構成して、以前のすべての割り当て中にブロックを段階的に解放し、説明されている特定のシナリオが発生しないようにすることです。これは、スレッド分散の作業ペースのガベージ コレクションとして知られています。
Hard Realtime Garbage Collectors に関する Siebert 博士の本では、これを達成する方法が説明されており、O(N) 操作にならずに、ガベージ コレクターがアプリケーションに追いつくという正式な証明が示されています。
リアルタイム ガベージ コレクションがいくつかのことを意味することを理解することは非常に重要です。
セーフティ クリティカルなアプリケーションにはハード リアルタイム ガベージ コレクションが必要ですが、ミッション クリティカルな汎用 Java アプリケーションでも使用できます。ハード リアルタイム ガベージ コレクタの使用に固有の制限はありません。一般的な使用では、ガベージ コレクターの長い一時停止がないため、よりスムーズなプログラムの実行が期待できます。
私にとって、100% リアルタイムの Java は、いまだに行き当たりばったりのテクノロジですが、専門家であるとは言いません。
これらの記事を読むことをお勧めします - Cliff Click blog。彼は Azul のアーキテクトであり、標準的な 1.5 Java 並行クラスのほとんどすべてをコーディングしています。参考までに、Azul は、標準的な RT 要件だけでなく、非常に大きなヒープ サイズを必要とするシステム向けに設計されています。
Sunは、リアルタイムのガベージコレクターを広範囲に文書化し、ここで自分で実行できるベンチマークを提供しています。他の人は、他の主要な生産グレードのRTGCアルゴリズムであるメトロノームについて言及しました。RT JVMの他の多くのベンダーには、独自の実装があります。ここにあるベンダーのリストを参照してください。それらのほとんどは、広範なドキュメントを提供しています。
特にアビオニクス/フライトソフトウェアに関心がある場合は、アビオニクス業界に特化したRTSJベンダーである aicasをご覧になることをお勧めします。Siebert博士(aicas CEO)のホームページには、PERCのGC実装について詳細に説明している学術出版物がいくつか掲載されています。
これは GC ではありませんが、単純な使用法で使用できる単純な O(1) 固定サイズのブロック割り当て/解放スキームがあります。たとえば、固定サイズのブロックの空きリストを使用できます。
struct Block {
Block *next;
}
Block *free_list = NULL; /* you will need to populate this at start, an
* easy way is to just call free on each block you
* want to add */
void release(void *p) {
if(p != NULL) {
struct Block *b_ptr = (struct Block *)p;
b_ptr->next = free_list;
free_list = b_ptr;
}
}
void *acquire() {
void *ret = (void *)free_list;
if(free_list != NULL) {
free_list = free_list->next;
}
return ret;
}
/* call this before you use acquire/free */
void init() {
/* example of an allocator supporting 100 blocks each 32-bytes big */
static const int blocks = 100;
static const int size = 32;
static unsigned char mem[blocks * size];
int i;
for(i = 0; i < blocks; ++i) {
free(&mem[i * size]);
}
}
それに応じて計画する場合は、設計を動的割り当ての特定のサイズのみに制限し、潜在的なサイズごとに free_list を用意することができます。C++ を使用している場合は、scoped_ptr (サイズごとにテンプレート パラメータを使用します) のような単純なものを実装して、より単純でありながら O(1) メモリ管理を実現できます。
唯一の本当の注意点は、二重の解放から保護されないこと、または取得からのものではないリリースに誤って ptr を渡してしまうことさえあるということです。
この投稿が少し古いことは承知していますが、興味深い調査を行ったので、更新したいと思います。
Deterministic GC は、Azul Systems の「Zing JVM」および JRocket によって提供されます。Zing には非常に興味深い機能が追加されており、「100% ソフトウェア ベース」になっています (x86 マシンで実行できます)。現時点ではLinuxのみですが...
価格: Java 6 以前を使用している場合、Oracle は 300% のアップリフトを請求し、この機能のサポートを強制しています (プロセッサあたり 15,000 ドル & サポート 3,300 ドル)。Azul、私が聞いたところによると、約 10,000 ドルから 12,000 ドルですが、コア/プロセッサではなく、物理マシンごとに課金されます。また、プロセスはボリュームごとに段階的に行われるため、利用するサーバーが多いほど、割引が深くなります. 彼らとの会話は、彼らが非常に柔軟であることを示しました。Oracle は永久ライセンスで、Zing はサブスクリプション ベースですが、計算して Zing が持つ他の機能を追加すると (以下の違いを参照)。
Java 7 に移行することでコストを削減できますが、開発コストが発生します。Oracle のロードマップ (約 18 か月ごとに新しいリリース) と、歴史的に Java SE アップデートの最新バージョンと 1 つ古いバージョンのみを無料で提供しているという事実を考えると、「無料」期間は最初の GA から 3 年間と予想されます。メジャー バージョンがある場合はリリースします。通常、最初の GA リリースは 12 ~ 18 か月間は本番環境に採用されず、本番システムを新しい主要な Java リリースに移行するには通常大きなコストがかかるため、Java SE のサポート料金は最初の展開から 6 ~ 24 か月の間に発生し始めることを意味します。 .
注目すべき相違点: JRocket には、RAM に関してまだスケーラビリティの制限がいくつかあります (昔から改善されていますが)。少しの調整で結果を改善できます。Zing は、継続的かつ同時の圧縮を可能にするアルゴリズムを設計しました (世界の一時停止や「チューニング」は必要ありません)。これにより、Zing は理論上のメモリ上限なしでスケーリングできます (世界の停止やクラッシュに苦しむことなく、300 GB 以上のヒープを実行しています)。パラダイム チェンジャーについて話します (ビッグ データへの影響を考えてください)。Zing では、ロックに非常に優れた改良が加えられており、少しの作業で驚くべきパフォーマンスが得られます (調整すれば、平均で 1 ミリ秒未満になる可能性があります)。最後に、本番環境でのクラス、メソッド、およびスレッドの動作を可視化できます (オーバーヘッドなし)。これは、更新を検討する際の大幅な時間の節約になると考えています。パッチ、およびバグ修正 (リークやロックなど)。これにより、開発/テストで多くの問題を再現する必要が実質的になくなります。
私が見つけたJVMデータへのリンク:
次の博士論文CMU-CS-01-174 - Scalable Real-time Parallel Garbage Collection for Symmetric Multiprocessors で運が良いかもしれません 。
azul システムには、GC がハードウェア支援の jvm があることを知っています。また、同時に実行して大量のデータを非常に高速に収集することもできます。
ただし、それがどれほど決定論的かはわかりません。