web-dev-qa-db-ja.com

C ++にガベージコレクターがないのはなぜですか?

そもそもガベージコレクションのメリットがあるため、この質問はしていません。私にこれを尋ねる主な理由は、Bjarne StroustrupがC++にはある時点でガベージコレクターがあると言っていることを知っているからです。

とはいえ、なぜ追加されていないのですか? C++用のガベージコレクターが既にいくつかあります。これは、「やるよりも簡単」というタイプのものの1つにすぎませんか?または、追加されていない(およびC++ 11で追加されない)他の理由がありますか?

クロスリンク:

明確にするために、最初に作成されたときにC++にガベージコレクターがなかった理由を理解しています。なぜコレクターを追加できないのか疑問に思っています。

253
Jason Baker

暗黙的なガベージコレクションを追加することもできましたが、それでもうまくいきませんでした。おそらく実装の複雑さだけでなく、人々が十分な速さで一般的なコンセンサスに達することができないためです。

Bjarne Stroustrup自身からの引用:

オプションで有効にできるガベージコレクターがC++ 0xの一部になることを期待していましたが、そのようなコレクターが他の言語とどのように統合されるかの詳細な仕様でやらなければならない十分な技術的問題がありました、提供されている場合。基本的にすべてのC++ 0x機能の場合と同様に、実験的な実装が存在します。

トピックの良い議論があります here

一般的な概要:

C++は非常に強力で、ほとんど何でもできます。このため、パフォーマンスに影響する可能性のある多くのものが自動的にプッシュされることはありません。ガベージコレクションは、スマートポインター(参照カウントでポインターをラップするオブジェクトで、参照カウントが0に達すると自動的に削除される)を使用して簡単に実装できます。

C++は、ガベージコレクションがない競合他社を念頭に置いて構築されました。効率性は、C++がCやその他と比較して批判をかわさなければならない主な関心事でした。

ガベージコレクションには2種類あります...

明示的なガーベッジコレクション:

C++ 0xには、shared_ptrで作成されたポインターを介したガベージコレクションがあります。

あなたがそれを望むなら、あなたはそれを使うことができます、あなたがそれを望まないなら、あなたはそれを使うことを強いられません。

C++ 0xを待ちたくない場合は、現在boost:shared_ptrも使用できます。

暗黙的なガベージコレクション:

ただし、透過的なガベージコレクションはありません。ただし、将来のC++仕様の焦点になります。

Tr1に暗黙的なガベージコレクションがないのはなぜですか?

C++ 0xのtr1が持つべき多くのことがあります、以前のインタビューでBjarne Stroustrupはtr1が彼が望んだほど多くを持っていなかったと述べました。

149
Brian R. Bondy

ここで議論に追加します。

ガベージコレクションには既知の問題があり、それらを理解すると、C++に何も存在しない理由を理解するのに役立ちます。

1。パフォーマンス?

最初の不満は多くの場合パフォーマンスに関するものですが、ほとんどの人は自分が何について話しているのか本当に理解していません。 Martin Beckettで示されているように、問題はパフォーマンスそのものではなく、パフォーマンスの予測可能性である可能性があります。

現在、広く展開されているGCの2つのファミリがあります。

  • マークアンドスイープの種類
  • 参照カウントの種類

Mark And Sweepは高速ですが(全体的なパフォーマンスへの影響は少ない)、「世界の凍結」シンドロームの影響を受けます。つまり、GCが起動すると、GCがクリーンアップするまで他のすべてが停止します。数ミリ秒で応答するサーバーを構築したい場合...一部のトランザクションは期待どおりに動作しません:)

Reference Countingの問題は異なります。アトミックカウントが必要なため、参照カウントは特にマルチスレッド環境でオーバーヘッドを追加します。さらに、参照サイクルの問題があるため、それらのサイクルを検出して除去するための巧妙なアルゴリズムが必要です(頻度は少ないものの、一般に「フリーズザワールド」でも実装できます)。一般に、今日の時点で、この種類は(通常、より応答性が高いか、むしろフリーズの頻度が低いにもかかわらず)Mark And Sweepよりも低速です。

Eiffelの実装者が、「Freeze The World」の側面を持たないReference Countingと同様のグローバルパフォーマンスを持つMark And Sweepガベージコレクターを実装しようとしている論文を見ました。 GC用に別のスレッドが必要でした(通常)。アルゴリズムは少し怖いものでした(最後は)が、この論文は概念を一度に1つずつ紹介し、アルゴリズムの「単純な」バージョンから本格的なものへの進化を示すのに良い仕事をしました。 PDFファイルに手を戻すことができる場合にのみ読むことをお勧めします...

2。リソースの取得は初期化

C++の一般的なイディオムでは、オブジェクト内のリソースの所有権をラップして、それらが適切に解放されるようにします。ガベージコレクションがないため、主にメモリに使用されますが、他の多くの状況にも役立ちます。

  • ロック(マルチスレッド、ファイルハンドルなど)
  • 接続(データベース、別のサーバーなど)

その考えは、オブジェクトの寿命を適切に制御することです:

  • あなたがそれを必要とする限り、それは生きているべきです
  • 使い終わったら殺すべきです

GCの問題は、前者を助け、最終的には後のことを保証する場合...この「究極の」では十分でないかもしれないということです。ロックを解除する場合、それ以上の呼び出しをブロックしないように、今すぐロックを解除することが本当に必要です!

GCを使用する言語には、2つの回避策があります。

  • スタックの割り当てが十分な場合はGCを使用しないでください。通常はパフォーマンスの問題のためですが、この場合はスコープが有効期間を定義するため、本当に役立ちます。
  • usingコンストラクト...しかし、C++のRAIIは暗黙的であるため、明示的に(弱い)RAIIであるため、ユーザーは無意識のうちにエラーを作成できません(usingキーワードを省略して)

。スマートポインター

スマートポインターは、C++のメモリを処理するための銀色の弾丸として表示されることがよくあります。多くの場合、聞いたことがあります:スマートポインターがあるため、結局GCは必要ありません。

間違いはもうありません。

スマートポインターは役立ちます。auto_ptrunique_ptrはRAIIの概念を使用しており、非常に便利です。それらはとても簡単なので、自分で簡単に書くことができます。

ただし、所有権を共有する必要がある場合はより困難になります。複数のスレッド間で共有する場合があり、カウントの処理にいくつかの微妙な問題があります。したがって、当然、shared_ptrに進みます。

それは素晴らしいです、それは結局Boostのためのものですが、それは特効薬ではありません。実際、shared_ptrの主な問題は、Reference Countingによって実装されるGCをエミュレートすることですが、サイクル検出をすべて自分で実装する必要があります... Urg

もちろん、このweak_ptrがありますが、これらのサイクルのためにshared_ptrを使用しているにもかかわらず、残念ながら既にメモリリークが発生しています。マルチスレッド環境では、検出が非常に困難です。

4。解決策は何ですか?

特効薬はありませんが、いつものように、間違いなく実行可能です。 GCがない場合、所有権を明確にする必要があります。

  • 可能であれば、一度に1人の所有者を持つことを好む
  • そうでない場合は、クラス図に所有権に関連するサイクルがないことを確認し、weak_ptrの微妙なアプリケーションでそれらを壊します

確かに、GCを持っているのは素晴らしいことです...しかし、些細な問題ではありません。それまでの間、袖をまくり上げるだけです。

137
Matthieu M.

どんなタイプ?組み込みの洗濯機コントローラー、携帯電話、ワークステーション、またはスーパーコンピューター向けに最適化する必要がありますか?
GUIの応答性またはサーバーのロードを優先すべきですか?
大量のメモリまたは大量のCPUを使用する必要がありますか?

C/c ++は、非常に多くの異なる状況で使用されます。ほとんどのユーザーには、スマートポインターのブーストなどで十分だと思います

編集-自動ガベージコレクターはパフォーマンスの問題ではありません(いつでもサーバーを追加購入できます)。これは予測できないパフォーマンスの問題です。
GCがいつ開始されるのかわからないということは、ほとんどの場合彼らが優れているというナルコレプシー航空パイロットを採用するようなものですが、本当に応答性が必要な場合です!

54
Martin Beckett

C++にガベージコレクションが組み込まれていない最大の理由の1つは、デストラクタを使用してガベージコレクションを再生することが本当に難しいことです。私の知る限り、まだ完全にそれを解決する方法を知っている人はいません。対処すべき問題がたくさんあります。

  • オブジェクトの確定的なライフタイム(参照カウントはこれを提供しますが、GCは提供しません。それほど大したことではないかもしれませんが)。
  • オブジェクトがガベージコレクトされているときにデストラクタがスローするとどうなりますか?ほとんどの言語は、この例外を転送できるcatchブロックがないため、この例外を無視しますが、これはおそらくC++の許容可能な解決策ではありません。
  • 有効/無効にする方法は?当然、コンパイル時の決定でしょうが、GC向けに記述されたコードとNOT GC向けに記述されたコードは大きく異なり、おそらく互換性がありません。これをどのように調整しますか?

これらは、直面している問題のほんの一部です。

33
Greg Rogers

これはoldの質問ですが、まだ対処されていない問題が1つあります。ガベージコレクションを指定することはほとんど不可能です。

特に、C++標準では、実装がその動作を実現する方法ではなく、外部で観察可能な動作の観点から言語を指定することに非常に注意しています。ただし、ガベージコレクションの場合、isには、外部から観察可能な動作はほとんどありません。

ガベージコレクションの一般的な考え方は、メモリの割り当てが成功することを保証するための合理的な試みを行う必要があるということです。残念ながら、たとえガベージコレクタが動作していても、メモリの割り当てが成功することを保証することは本質的に不可能です。これはどのような場合でもある程度当てはまりますが、特にC++の場合はそうです。なぜなら、コレクションサイクル中にメモリ内のオブジェクトを移動するコピーコレクター(または同様のもの)を(おそらく)使用できないからです。

オブジェクトを移動できない場合、割り当てを行うための単一の連続したメモリスペースを作成することはできません。つまり、ヒープ(または空きストア、または呼び出したいもの)ができることを意味します。 、時間の経過とともに断片化します。これにより、要求された量よりも多くのメモリが空いている場合でも、割り当てが成功しなくなります。

someを思いつくことができるかもしれませんが、(本質的に)まったく同じ割り当てパターンを繰り返し繰り返して成功したことを保証します最初に、割り当てられたメモリが反復間でアクセスできなくなった場合、後続の反復で成功し続けます。それは本質的に役に立たないという非常に弱い保証ですが、それを強化する合理的な希望は見当たりません。

それでも、C++で提案されているものよりも強力です。 以前の提案 [警告:PDF](ドロップされた)は、何も保証しませんでした。 28ページの提案で、外部から観察可能な行動の邪魔になったのは、次のような1つの(非規範的な)メモでした。

[注:ガベージコレクションプログラムの場合、高品質のホスト型実装では、回収する到達不能メモリの量を最大化することを試みる必要があります。 —注を終了]

少なくとも私にとっては、これは投資収益率に関する深刻な質問を提起します。既存のコードを壊し(正確にはどれだけの量かは確かではありませんが、間違いなくかなり)、実装に新しい要件を課し、コードに新しい制限を課します。

たとえせいぜい、 Javaでのテスト に基づいたプログラムは、おそらく現在と同じ速度で実行するために約6倍のメモリを必要とするプログラムです。さらに悪いことに、ガベージコレクションは最初からJavaの一部でした-C++はガベージコレクタにさらに十分な制限を課し、ほぼ確実に偶数worse費用便益比(提案が保証する範囲を超えて、何らかの便益があると仮定した場合でも)。

私は状況を数学的に要約します。これは複雑な状況です。数学者なら誰でも知っているように、複素数には実数部と虚数部の2つの部分があります。ここで私たちが持っているのは現実のコストですが、(少なくともほとんど)想像上のメリットがあるように思えます。

20
Jerry Coffin

自動ガベージコレクションが必要な場合は、C++用の商用およびパブリックドメインの優れたガベージコレクタがあります。ガベージコレクションが適しているアプリケーションの場合、C++は、他のガベージコレクション言語と比較して優れたパフォーマンスを持つ優れたガベージコレクション言語です。 C++の自動ガベージコレクションについては、 The C++ Programming Language(4rd Edition) を参照してください。 Hans-Jも参照してください。 CおよびC++ガベージコレクション用のBoehmの サイトarchive )。

また、C++は、メモリ管理が 安全で、ガベージコレクタなしで暗黙的になるプログラミング技術をサポートしています 。ガベージコレクションは最後の選択であり、リソース管理のための不完全な処理方法だと考えています。それは、多くの状況でより良いアプローチがあるというだけで、それが決して役に立たないという意味ではありません。

ソース: http://www.stroustrup.com/bs_faq.html#garbage-collection

それが組み込まれていない理由については、GCがthingになる前に発明されたことを正しく覚えていれば、いくつかの理由で言語がGCを持っていたとは思わない(IE Backwardsとの互換性C)

お役に立てれば。

15
Rayne

Stroustrupは、2013 Going Nativeカンファレンスでこれについて良いコメントをしました。

このビデオ で約25分50秒までスキップしてください。 (ビデオ全体を実際に見ることをお勧めしますが、これはガベージコレクションに関するものにスキップします。)

オブジェクトと値を直接的な方法で処理することを簡単に(そして安全で、予測可能で、読みやすく、教えやすい)本当に素晴らしい言語がある場合、ヒープ、ガベージコレクションwantもしません。

最新のC++およびC++ 11にあるものでは、ガベージコレクションは限られた状況を除いて望ましくありません。実際、優れたガベージコレクターが主要なC++コンパイラーの1つに組み込まれていても、それほど頻繁には使用されないと思います。 GCを回避するのは難しくなく、簡単です

彼はこの例を示しています:

void f(int n, int x) {
    Gadget *p = new Gadget{n};
    if(x<100) throw SomeException{};
    if(x<200) return;
    delete p;
}

これはC++では安全ではありません。しかし、Javaでも安全ではありません! C++では、関数が早期に戻る場合、deleteが呼び出されることはありません。ただし、Javaのように完全なガベージコレクションがある場合は、オブジェクトが「将来のある時点で」破壊されるという提案を受け取るだけです(Update:さらに悪いことに、これはJavaがnotファイナライザーを呼び出すことを約束します-呼び出されない可能性があります)。ガジェットが開いているファイルハンドル、データベースへの接続、または後でデータベースに書き込むためにバッファリングしたデータを保持している場合、これは十分ではありません。これらのリソースをできるだけ早く解放するために、ガジェットが終了したらすぐに破棄する必要があります。不要になった数千のデータベース接続にデータベースサーバーが苦労するのは望ましくありません。プログラムの動作が終了したことはわかりません。

それで解決策は何ですか?いくつかのアプローチがあります。大部分のオブジェクトに使用する明白なアプローチは次のとおりです。

void f(int n, int x) {
    Gadget p = {n};  // Just leave it on the stack (where it belongs!)
    if(x<100) throw SomeException{};
    if(x<200) return;
}

これにより、入力する文字が少なくなります。邪魔になるnewはありません。 Gadgetを2回入力する必要はありません。オブジェクトは、関数の最後で破棄されます。これがあなたの望むものであれば、これは非常に直感的です。 Gadgetsは、intまたはdoubleと同じように動作します。予測可能で、読みやすく、教えやすい。すべてが「価値」です。大きな値になることもありますが、ポインタ(または参照)で得られるこの「離れた場所でのアクション」を持たないため、値を教えるのは簡単です。

作成するオブジェクトのほとんどは、それらを作成した関数でのみ使用され、おそらく子関数への入力として渡されます。プログラマは、オブジェクトを返すとき、またはソフトウェアの広く分離された部分でオブジェクトを共有するときに、「メモリ管理」について考える必要はありません。

範囲と寿命は重要です。ほとんどの場合、有効期間がスコープと同じであれば簡単です。理解しやすく、教えるのも簡単です。別のライフタイムが必要な場合は、たとえばshared_ptrを使用して、これを実行しているコードを読むのは明らかです。 (または、移動セマンティクスまたはunique_ptrを利用して、値ごとに(大きな)オブジェクトを返します。

これは効率の問題のように思えるかもしれません。 foo()からガジェットを返したい場合はどうすればよいですか? C++ 11の移動セマンティクスにより、大きなオブジェクトを簡単に返すことができます。 Gadget foo() { ... }を書くだけで、動作し、すぐに動作します。自分で&&をいじる必要はありません。値で値を返すだけで、言語は必要な最適化を行うことができます。 (C++ 03以前でも、コンパイラは不必要なコピーを回避するのに非常に良い仕事をしていました。)

Stroustrupがビデオの他の場所(言い換え)で述べたように: "コンピューター科学者だけがオブジェクトをコピーし、オリジナルを破壊することを主張するだろう(聴衆は笑う)。新しい場所へ?これは人間(コンピューター科学者ではない)が期待することです。 "

オブジェクトのコピーが1つしか必要ないことを保証できる場合、オブジェクトの有効期間を理解するのがはるかに簡単です。必要なライフタイムポリシーを選択できます。必要に応じてガベージコレクションがあります。しかし、他のアプローチの利点を理解すると、ガベージコレクションが設定リストの一番下にあることがわかります。

それがうまくいかない場合は、unique_ptrを使用するか、失敗した場合はshared_ptrを使用できます。よく書かれたC++ 11は、メモリ管理に関しては、他の多くの言語よりも短く、読みやすく、簡単に教えることができます。

12
Aaron McDaid

C++の背後にある考え方は、使用しない機能に対してパフォーマンスへの影響を一切与えないというものでした。したがって、ガベージコレクションを追加すると、Cのようにハードウェア上で直接実行されるプログラムと、ある種のランタイム仮想マシン内で実行されるプログラムが必要になります。

サードパーティのガベージコレクションメカニズムにバインドされているスマートポインターの形式を使用することを妨げるものは何もありません。 MicrosoftがCOMでそのようなことをしたことを思い出すようですが、うまくいきませんでした。

10
Uri

C++に関するほとんどの「なぜ」質問に答えるには、 C++の設計と進化 を読んでください。

8

現代のC++はガベージコレクションを必要としないためです。

Bjarne StroustrupのFAQ この問題に関する答えは言う

私はゴミが好きではありません。ポイ捨てが好きではありません。私の理想は、ガベージを生成しないことでガベージコレクターの必要性を排除することです。それが可能になりました。


最近作成されたコード(C++ 17および公式の コアガイドライン に従う)の状況は次のとおりです。

  • ほとんどのメモリ所有権関連のコードは、ライブラリ(特にコンテナを提供するライブラリ)にあります。
  • メモリの所有権を含むコードのほとんどのuseはRAII パターン の後に続くため、構築時に割り当てが行われ、破棄時に割り当て解除が行われます。何かが割り当てられたスコープを出るとき。
  • メモリを直接明示的に割り当てまたは割り当て解除しないでください
  • 生のポインタ メモリを所有しない (ガイドラインに従っている場合)、それらを渡すことでリークすることはできません。
  • メモリ内の値のシーケンスの開始アドレスをどのように渡すのか疑問に思っている場合は、 span ;でそれを行うことになります。生のポインタは必要ありません。
  • 所有する「ポインター」が本当に必要な場合は、C++を使用します。 標準ライブラリスマートポインター -リークすることはなく、非常に効率的です。または、 "owner pointers" を使用して、スコープの境界を越えて所有権を渡すことができます。これらは一般的ではなく、明示的に使用する必要があります。また、リークに対する部分的な静的チェックが可能になります。

「ええ?でも….

...昔のC++を書くのと同じようにコードを書いたら?」

確かに、あなたはcouldすべてのガイドラインを無視し、漏れやすいアプリケーションコードを書くだけです-そしていつものようにコンパイルして実行します(そして漏れます)。

しかし、開発者が好意的であり、多くの自己管理を行うことが期待される「それをしないで」という状況ではありません。準拠していないコードを書くのは簡単ではなく、書くのも速くありませんし、パフォーマンスも良くありません。また、準拠するコードが提供および期待するものとの「インピーダンスの不一致」の増大に直面するため、徐々に作成することも難しくなります。

...私がreintrepret_castなら?または、ポインター演算を行いますか?または他のそのようなハッキング?」

確かに、気をつければ、ニースをガイドラインでプレイしているにもかかわらず、物事を台無しにするコードを書くことができます。しかし:

  1. これを行うことはめったにありません(コード内の場所に関して、必ずしも実行時間の割合に関してではありません)
  2. これは偶然ではなく意図的に行うだけです。
  3. そうすることは、ガイドラインに準拠したコードベースで際立っています。
  4. とにかく別の言語でGCをバイパスするようなコードです。

...ライブラリ開発?」

あなたがC++ライブラリの開発者であれば、生のポインタを含む安全でないコードを書きます、そしてあなたは注意深く責任を持ってコーディングする必要があります-しかし、これらは専門家によって書かれた自己完結型のコードです(そしてもっと重要なのは専門家によってレビューされています)。


それで、Bjarneが言ったように:一般的にゴミを収集する動機はありません。 GCはC++で問題になりつつあります。

それは、GCが特定のアプリケーションにとって興味深い問題ではないということではありません。カスタム割り当てと割り当て解除の戦略を採用したいときです。これらの場合、言語レベルのGCではなく、カスタムの割り当てと割り当て解除が必要になります。

7
einpoklum

元のC言語の背後にある基本原則の1つは、メモリは一連のバイトで構成され、コードはそれらのバイトが使用されている正確な瞬間に何を意味するかだけを考慮する必要があるということです。最新のCでは、コンパイラーは追加の制限を課すことができますが、Cには、ポインターをバイトシーケンスに分解し、同じ値を含むバイトシーケンスをポインターに組み立てて、そのポインターを使用して、以前のオブジェクトにアクセスします。

ある種のアプリケーションでは、その機能は有用な場合がありますが、不可欠な場合もありますが、その機能を含む言語は、あらゆる種類の有用で信頼性の高いガベージコレクションをサポートする能力が非常に制限されます。コンパイラーがポインターを構成するビットで行われたすべてのことを知らない場合、ポインターを再構築するのに十分な情報が宇宙のどこかに存在するかどうかを知る方法がありません。その情報を知っていてもコンピュータがアクセスできない方法でその情報を保存することが可能であるため(たとえば、ポインタを構成するバイトは、誰かが書くのに十分な長さで画面に表示されていたかもしれません)それらを紙に書き留めておく)、ポインターが将来使用される可能性があるかどうかをコンピューターが知ることは文字通り不可能かもしれません。

多くのガベージコレクションフレームワークの興味深い特徴は、オブジェクト参照が、そこに含まれるビットパターンではなく、オブジェクト参照に保持されるビットと他の場所に保持されるその他の情報との関係によって定義されることです。 CおよびC++では、ポインターに格納されているビットパターンがオブジェクトを識別する場合、そのビットパターンは、オブジェクトが明示的に破棄されるまでそのオブジェクトを識別します。典型的なGCシステムでは、オブジェクトはある時点でビットパターン0x1234ABCDで表されますが、次のGCサイクルは0x1234ABCDへのすべての参照を0x4321BABEへの参照に置き換え、オブジェクトは後者のパターンで表されます。オブジェクト参照に関連付けられたビットパターンを表示し、後でキーボードから読み取ったとしても、同じオブジェクト(または任意のオブジェクト)を識別するために同じビットパターンを使用できるとは考えられません。

4
supercat

技術的な話はすべて、コンセプトを複雑化しすぎています。

GCをすべてのメモリのC++に自動的に配置する場合は、Webブラウザーのようなものを検討してください。 Webブラウザは、完全なWebドキュメントをロードし、Webスクリプトを実行する必要があります。ドキュメントスクリプトにWebスクリプト変数を保存できます。多くのタブが開いているブラウザのBIGドキュメントでは、GCが完全なコレクションを実行するたびに、すべてのドキュメント要素もスキャンする必要があることを意味します。

ほとんどのコンピューターでは、これはページフォールトが発生することを意味します。したがって、質問に答える主な理由は、ページフォールトが発生することです。これは、PCが大量のディスクアクセスを開始したときにわかります。これは、無効なポインターを証明するためにGCが大量のメモリにアクセスする必要があるためです。大量のメモリを使用する正真正銘のアプリケーションがある場合、ページフォールトのために、すべてのコレクションをすべてのコレクションをスキャンする必要があります。ページフォールトとは、仮想メモリをディスクからRAMに読み戻す必要がある場合です。

したがって、正しい解決策は、アプリケーションをGCが必要な部分とそうでない部分に分割することです。上記のWebブラウザの例の場合、ドキュメントツリーがmallocで割り当てられていたが、javascriptがGCで実行された場合、GCが起動するたびにメモリの小さな部分とメモリのすべてのPAGED OUT要素のみがスキャンされますドキュメントツリーをページに戻す必要はありません。

この問題をさらに理解するには、仮想メモリと、それがコンピューターにどのように実装されているかを調べてください。 RAMがそれほど多くないときに、プログラムで2GBを使用できるという事実がすべてです。 32GBItシステム用の2GB RAMを備えた最新のコンピューターでは、1つのプログラムのみが実行されている限り、このような問題はありません。

追加の例として、すべてのオブジェクトをトレースする必要がある完全なコレクションを検討してください。まず、ルート経由で到達可能なすべてのオブジェクトをスキャンする必要があります。次に、手順1で表示されているすべてのオブジェクトをスキャンします。次に、待機中のデストラクターをスキャンします。次に、すべてのページに再度移動し、非表示のオブジェクトをすべてオフにします。これは、多くのページが何度もスワップアウトされたり戻ったりする可能性があることを意味します。

つまり、すべてのメモリに触れた結果として発生するページフォールトの数が原因で、プログラム内のすべてのオブジェクトの完全なGCが実行不可能になるため、プログラマはスクリプトなどの補助としてGCを表示する必要がありますデータベースは動作しますが、手動のメモリ管理で通常のことを行います。

そしてもちろん、他の非常に重要な理由はグローバル変数です。コレクターがグローバル変数ポインターがGCにあることを知るには、特定のキーワードが必要になるため、既存のC++コードは機能しません。

3
Bob Holmes

短い回答:ガベージコレクションを効率的に(わずかな時間とスペースのオーバーヘッドで)実行し、常に正しく実行する方法(すべての可能な場合)がわかりません。

長い答え:Cと同様に、C++はシステム言語です。つまり、オペレーティングシステムなどのシステムコードを記述するときに使用されます。つまり、C++は、Cと同じように、パフォーマンスを主なターゲットとして設計されています。言語の標準では、パフォーマンスの目標を妨げる可能性のある機能は追加されません。

これで質問が一時停止します:ガベージコレクションがパフォーマンスを妨げるのはなぜですか?主な理由は、すべての場合において、実装に関しては、最小限のオーバーヘッドでガベージコレクションを行う方法がわからないということです。したがって、C++コンパイラとランタイムシステムが常にガベージコレクションを効率的に実行することは不可能です。一方、C++プログラマーは、彼の設計/実装を知っている必要があり、ガベージコレクションの最適な実行方法を決定するのに最適な人物です。

最後に、制御(ハードウェア、詳細など)およびパフォーマンス(時間、スペース、電力など)が主な制約でない場合、C++は書き込みツールではありません。他の言語は、必要なオーバーヘッドとともに、より適切に機能し、より多くの[隠された]ランタイム管理を提供します。

3
Sqandr

C++とJavaを比較すると、C++が暗黙のガベージコレクションを念頭に置いて設計されていないのに、Javaが設計されていることがすぐにわかります。

Cスタイルの任意のポインタや決定論的なデストラクタのようなものがあると、GC実装の​​パフォーマンスが低下するだけでなく、大量のC++レガシーコードの後方互換性も破壊されます。

それに加えて、C++は、複雑なランタイム環境を持たずにスタンドアロンの実行可能ファイルとして実行することを目的とした言語です。

全体として:はい、ガベージコレクションをC++に追加することは可能ですが、継続性のために、そうしない方が良いでしょう。そうすることのコストは、利益よりも大きくなります。

3
Mike76

ガベージコレクションを課すことは、実際には低レベルから高レベルのパラダイムシフトです。

ガベージコレクションを使用した言語での文字列の処理方法を見ると、高レベルの文字列操作関数のみが許可され、文字列へのバイナリアクセスは許可されていません。簡単に言えば、すべての文字列関数は最初にポインターをチェックして、文字列がどこにあるかを確認します(1バイトだけを描画している場合でも)。したがって、ガベージコレクションを使用して言語の文字列の各バイトを処理するループを実行している場合、文字列がいつ移動したかを知ることができないため、各反復のベース位置とオフセットを計算する必要があります。次に、ヒープ、スタック、スレッドなどについて考える必要があります。

0
www-0av-Com

主に2つの理由:

  1. 必要ないから(IMHO)
  2. C++の基礎であるRAIIとはほとんど互換性がないため

C++はすでに手動メモリ管理、スタック割り当て、RAII、コンテナ、自動ポインタ、スマートポインタを提供しています...それで十分でしょう。ガベージコレクターは、誰がどのオブジェクトを所有すべきか、いつリソースを解放すべきかを5分間考えたくない怠laなプログラマー向けです。これは、C++でのやり方ではありません。

0
Marc Coll