ガベージ コレクションは、リークを最悪の悪夢にする可能性があります
循環参照などを処理する本格的な GC は、ref-counted よりも多少アップグレードされますshared_ptr
。C++ ではいくらか歓迎しますが、言語レベルでは歓迎しません。
C++ の優れている点の 1 つは、ガベージ コレクションを強制しないことです。
よくある誤解を正したいと思います。それは、ガベージ コレクションによって何らかの形でリークが解消されるという神話です。私の経験から言うと、他の人が書いたコードをデバッグし、最もコストのかかる論理リークを見つけようとする最悪の悪夢は、リソース集約型のホスト アプリケーションを介した組み込み Python などの言語によるガベージ コレクションに関係していました。
GC のようなテーマについて話すときは、理論があり、次に実践があります。理論的には素晴らしく、漏れを防ぎます。しかし、理論的なレベルでは、すべての言語は素晴らしく、リークのないものです。理論的には、誰もが完全に正しいコードを書き、単一のコードがうまくいかない可能性のあるすべてのケースをテストするからです。
私たちのケースでは、ガベージ コレクションと理想的とは言えないチーム コラボレーションが組み合わされて、最悪の、最もデバッグが困難なリークが発生しました。
問題は依然としてリソースの所有権に関係しています。永続オブジェクトが関係する場合は、ここで明確な設計上の決定を行う必要がありますが、ガベージ コレクションを使用すると、そうではないと簡単に考えてしまいます。
R
開発者が常にコミュニケーションを取り合い、お互いのコードを常に慎重にレビューしているわけではない (私の経験ではあまりにも一般的なことです) チーム環境では、リソースが与えられた場合、開発者がA
そのリソースへのハンドルを保存するのは非常に簡単になります。 . 開発者B
も同様に、おそらくR
データ構造に間接的に追加するあいまいな方法で行います。そうC
です。ガベージ コレクション システムでは、これにより の所有者が 3 人作成されましたR
。
開発者は最初にリソースを作成した人であり、自分がその所有者であると考えているため、ユーザーがそのリソースをもう使用したくないことを示したときに、A
への参照を解放することを忘れないでください。R
結局のところ、そうしないと何も起こらず、ユーザー側の削除ロジックが何もしないことはテストから明らかです。そのため、十分に有能な開発者なら誰でもそうするように、彼はそれをリリースすることを覚えています。これは、それを処理するイベントをトリガーし、B
への参照を解放することも忘れませんR
。
しかし、C
忘れる。彼はチームの中で有能な開発者の 1 人ではありません。システムで働いて 1 年しか経っていないやや新人です。あるいは、彼はチームのメンバーでさえなく、多くのユーザーがソフトウェアに追加する製品用のプラグインを作成している、人気のあるサード パーティの開発者である可能性があります。ガベージ コレクションでは、サイレントな論理リソース リークが発生するのはこのときです。それらは最悪の種類です。ソフトウェアのユーザーに見える側に明らかなバグとして現れるとは限りません。プログラムを実行している間、メモリ使用量が不思議な目的のために増え続けているという事実に加えて。デバッガーでこれらの問題を絞り込むことは、時間に敏感な競合状態をデバッグするのと同じくらい楽しい場合があります。
ガベージ コレクションがなければ、開発者はダングリング ポインターC
を作成していたでしょう。ある時点でアクセスしようとして、ソフトウェアがクラッシュする可能性があります。これはテスト/ユーザーに表示されるバグです。少し恥ずかしくなり、バグを修正します。GC のシナリオでは、システムのどこでリークが発生しているかを突き止めるだけでも非常に難しく、一部のリークは決して修正されない場合があります。これらは、簡単に検出でき、特定のコード行を特定できるタイプの物理的なリークではありません。C
valgrind
ガベージ コレクションにより、開発者C
は非常に不可解なリークを作成しました。彼のコードは、ソフトウェア内の目に見えないエンティティにアクセスし続ける可能性がR
あり、この時点ではユーザーには関係ありませんが、有効な状態のままです。のC
コードがより多くのリークを作成するにつれて、彼は無関係なリソースでより多くの隠れた処理を作成し、ソフトウェアはメモリをリークするだけでなく、そのたびにますます遅くなります。
そのため、ガベージ コレクションによって論理リソースのリークが軽減されるとは限りません。理想的とは言えないシナリオでは、リークが気付かれずにソフトウェアに残りやすくなる可能性があります。開発者は、GC の論理リークを追跡しようとしてイライラする可能性があり、回避策として定期的にソフトウェアを再起動するようにユーザーに指示するだけです。ぶら下がっているポインターを排除します。また、どのようなシナリオでもクラッシュがまったく受け入れられない安全性重視のソフトウェアでは、GC を使用することをお勧めします。しかし、私は安全性がそれほど重要ではないが、リソースを集中的に使用し、パフォーマンスが重要な製品で作業していることがよくあります。そこでは、本当にあいまいで謎めいたサイレント バグよりも、すぐに修正できるクラッシュの方が望ましく、リソース リークは些細なバグではありません。
どちらの場合も、3D ソフトウェアのシーン グラフ、コンポジターで使用できるビデオ クリップ、ゲーム ワールドの敵など、スタックに常駐しない永続オブジェクトについて話しています。リソースの有効期間がスタックに結び付けられている場合、C++ とその他の GC 言語の両方で、リソースを適切に管理することが簡単になります。真の難しさは、他のリソースを参照する永続的なリソースにあります。
C または C++ では、誰がリソースを所有しているか、およびそれらへのハンドルをいつ解放する必要があるかを明確に指定できない場合 (例: イベントに応答して null に設定)、segfault に起因するダングリング ポインターとクラッシュが発生する可能性があります。しかし GC では、大声で不快だが、しばしば見つけやすいクラッシュが、決して検出されない可能性がある静かなリソース リークと交換されます。