web-dev-qa-db-ja.com

CやC ++などの言語にガベージコレクションがないのに、Javaにはあるのはなぜですか?

まあ、Cのmalloc/freeやC++のメモリ管理用のnew/using-destructorのようなものがあることは知っていますが、これらの言語にユーザーができる「新しい更新」がないのかと思っていましたメモリを手動で管理するオプション、またはシステムが自動的にメモリを管理するオプション(ガベージコレクション)がありますか?

ちょっと新しい質問ですが、CSに約1年しかいません。

58
Dark Templar

ガベージコレクションには、割り当ての追跡や参照カウントのためのデータ構造が必要です。これらは、メモリ、パフォーマンス、および言語の複雑さのオーバーヘッドを生み出します。 C++は「金属に近い」ように設計されています。つまり、機能とパフォーマンスのトレードオフのパフォーマンス面でのパフォーマンスが高くなります。他の言語では、そのトレードオフが異なります。これは、言語を選択する際の考慮事項の1つです。

とはいえ、C++には参照カウントのためのかなり軽量で高性能なスキームがたくさんありますが、それらは言語自体の一部ではなく、商用およびオープンソースのライブラリにあります。オブジェクトの有効期間を管理するための参照カウントは、ガベージコレクションと同じではありませんが、同じ種類の問題の多くに対処し、C++の基本的なアプローチに適しています。

72
kylben

厳密に言うと、C言語ではメモリ管理はまったくありません。 malloc()とfree()は言語のキーワードではなく、ライブラリから呼び出される関数です。 malloc()とfree()はC標準ライブラリの一部であり、Cの標準に準拠した実装によって提供されるため、この区別は今や陳腐なものになる可能性がありますが、これは以前は常に当てはまるとは限りませんでした。

メモリ管理の標準がない言語が必要なのはなぜですか?これは「ポータブルアセンブリ」としてCの起源に戻ります。専用のメモリ管理手法からメリットを得たり、必要なハードウェアやアルゴリズムの多くのケースがあります。私の知る限り、Javaのネイティブメモリ管理を完全に無効にして、独自のメモリ管理に置き換える方法はありません。これは、一部の高パフォーマンス/最小リソースの状況では、まったく受け入れられません。 Cは、プログラムが使用するインフラストラクチャを正確に選択できるほぼ完全な柔軟性を提供します。支払われた代償として、C言語では、バグのない正しいコードを作成するための支援がほとんど提供されません。

44

本当の答えは、安全で効率的なガベージコレクションメカニズムを作成する唯一の方法は、不透明な参照に対して言語レベルのサポートを使用することです。 (または、逆に、直接メモリ操作の言語レベルのサポートのlack。)

JavaとC#は、操作できない特別な参照型を持っているため、これを行うことができます。これにより、ランタイムは割り当てられたオブジェクトをメモリに移動するのようなことを自由に実行できます。これは、高性能のGC実装にとって重要です。

記録として、現代のGC実装では参照カウントを使用していませんなので、完全に赤のニシンです。最新のGCは世代別コレクションを使用します。新しい割り当ては、C++のような言語でのスタック割り当てと基本的に同じ方法で処理され、定期的にまだ有効な新しく割り当てられたオブジェクトは、別の「サバイバー」スペースと世代全体に移動されます。のオブジェクトが一度に割り当て解除されます。

このアプローチには長所と短所があります。利点は、GCをサポートする言語でのヒープ割り当てがスタック割り当てと同じくらい速い GCをサポートしない言語であり、欠点は、必要なオブジェクトであることです破棄される前にクリーンアップを実行するには、別のメカニズム(C#のusingキーワードなど)が必要か、クリーンアップコードが非決定的に実行されます。

高性能GCの重要な点の1つは、特別なクラスの参照を言語でサポートする必要があることです。 Cはこの言語をサポートしておらず、今後もサポートしません。 C++には演算子のオーバーロードがあるため、GCのポインター型をエミュレートできますが、慎重に行う必要があります。実際、MicrosoftがCLR(.NETランタイム)の下で実行されるC++の方言を発明したとき、彼らは "C#スタイルの参照"の新しい構文(例:Foo^)「C++スタイルの参照」と区別するために(例:Foo&)。

C++が持っているもの、およびC++プログラマーが通常使用するものはスマートポインターであり、これは実際には単なる参照カウントメカニズムです。参照カウントを「真の」GCとは見なしませんが、手動メモリ管理や真のGCよりもパフォーマンスは低下しますが、確定的な破壊という利点がありますが、同じ利点の多くを提供します。

結局のところ、答えは言語設計機能に要約されます。 Cは1つの選択を行い、C++はCとの下位互換性を可能にする一方で、ほとんどの目的に十分に適した代替手段を提供する選択を行い、JavaおよびC#は、 Cとの互換性はありませんが、ほとんどの目的には十分です。残念ながら、特効薬はありませんが、さまざまな選択肢に精通していると、現在ビルドしようとしているプログラムに適したものを選択するのに役立ちます。

32
Daniel Pryden

なぜなら、C++の機能を使用する場合には、その必要がないからです。

ハーブサッター:「私は何年も削除を書いていない。

参照 最新のC++コードの記述:C++は長年にわたってどのように進化してきたか 21:10

多くの経験豊富なC++プログラマーを驚かせるかもしれません。

27
Lior Kogan

「すべて」のガベージコレクターは、メモリ内に参照されていないオブジェクトがあるかどうか、およびそれらが削除されていないかどうかを定期的にチェックするプロセスです。 (はい、これは全体的な単純化であることを知っています)。これは言語のプロパティではなく、フレームワークです。

CおよびC++用に作成されたガベージコレクタがあります- これ など。

言語に「追加」されていない理由の1つは、メモリ管理に独自のコードを使用するため、決して使用しない既存のコードの膨大な量が原因である可能性があります。別の理由として、CおよびC++で記述されたタイプのアプリケーションは、ガベージコレクションプロセスに関連するオーバーヘッドを必要としないことがあります。

15
ChrisF

Cは、ガベージコレクションがほとんど選択肢のない時代に設計されました。また、最小限のメモリと最小限のランタイムサポートを備えたベアメタルのリアルタイム環境である、ガベージコレクションが一般的に機能しない用途も想定されていました。 Cは、64 * [〜#〜] k [〜#〜] *バイトのメモリを備えたpdp-11で実行された最初のUNIXの実装言語であったことを覚えておいてください。 C++はもともとCの拡張機能でした。選択はすでに行われており、ガベージコレクションを既存の言語に移植することは非常に困難です。これは、1階から組み込む必要がある種類のことです。

12
ddyer

正確な引用はありませんが、BjarneとHerb Sutterの両方が次のように言っています。

C++にはガベージがないため、ガベージコレクターは必要ありません。

最近のC++ではスマートポインターを使用しているため、ガベージはありません。

9
ronag

これらの言語がオプションのガベージコレクターを含むように更新されていない理由を尋ねます。

オプションのガベージコレクションの問題は、異なるモデルを使用するコードを混在させることができないことです。つまり、ガベージコレクターを使用していることを前提とするコードを記述した場合、ガベージコレクションがオフになっているプログラムではそれを使用できません。そうすると、どこにでも漏れてしまいます。

8
Winston Ewert

この質問に対する短くて退屈な答えは、ガベージコレクターを書く人々のために、ガベージコレクションされていない言語がそこにある必要があるということです。メモリレイアウトを非常に正確に制御できる言語を使用することは、概念的に簡単ではありませんandは、GCを実行しています。

もう1つの質問は、CとC++にガベージコレクタがない理由です。まあ、私はC++にそれらのいくつかがあることを知っていますが、それらはそもそもGCに対応するように設計されていない言語、および依然としてC++を使用している人々に対処することを強いられるため、あまり人気がありませんこの年齢は、GCに失敗するようなものではありません。

また、GCを使用していない古い言語にGCを追加する代わりに、GCをサポートしながら、ほとんど同じ構文を持つ新しい言語を作成する方が実際には簡単です。 JavaとC#はこの良い例です。

6
hugomg

ガベージコレクションを備えた言語でデバイスハンドラーを書くことを想像できますか? GCの実行中に、何ビットが回線に到達する可能性がありますか?

またはオペレーティングシステム?カーネルを起動する前に、ガベージコレクションの実行を開始するにはどうすればよいでしょうか。

Cは、ハードウェアタスクに近い低レベル向けに設計されています。問題?それはとても良い言語であり、多くのより高いレベルのタスクにも適しています。言語皇帝はこれらの使用法を認識していますが、デバイスドライバー、埋め込みコード、オペレーティングシステムの要件を優先的にサポートする必要があります。

6
James Anderson

を含む様々な問題があります...

  • GCはC++の前に、そしておそらくCの前に発明されましたが、GCが実用的であると広く認められる前に、CとC++の両方が実装されました。
  • 基になる非GC言語がないと、GC言語とプラットフォームを簡単に実装できません。
  • 一般的なタイムスケールなどで開発された一般的なアプリケーションコードの場合、GCは非GCよりも明らかに効率的ですが、開発努力を重ねることが適切なトレードオフであり、特殊なメモリ管理が汎用GCよりも優れているという問題があります。さらに、C++は通常、追加の開発作業を行わなくても、ほとんどのGC言語よりも明らかに効率的です。
  • GCは、C++スタイルのRAIIよりも普遍的に安全ではありません。 RAIIは、メモリ以外のリソースを自動的にクリーンアップできるようにします。これは、基本的に、信頼性が高くタイムリーなデストラクタをサポートするためです。参照サイクルに問題があるため、これらを従来のGCメソッドと組み合わせることはできません。
  • GC言語には、特有の種類のメモリリークがあります。特に、再び使用されることはないが、nullにされたり上書きされたりすることのない既存の参照が存在するメモリに関連します。これを明示的に行う必要性は、原則として、deleteまたはfreeを明示的に行う必要性と同じです。 GCアプローチには依然として利点があります-ぶら下がっている参照はありません-静的分析はいくつかのケースを捉えることができますが、すべてのケースに完璧な解決策はありません。

基本的に、それは部分的には言語の時代についてですが、とにかく少しGCの言語のための場所があります。そして真剣に、C++では、GCの欠如は大したことではありません。メモリの管理方法は異なりますが、管理されていません。

Microsoftが管理するC++には、少なくとも同じアプリケーションでGCと非GCを混合する機能があり、それぞれの利点を組み合わせることができますが、これが実際にどれほどうまく機能するかについては、経験がありません。

私の関連する回答への担当者リンク.

5
Steve314

ガベージコレクションは、DMA対応ハードウェアのドライバーの開発に使用されるシステム言語とは基本的に互換性がありません。

オブジェクトへの唯一のポインタが一部の周辺機器のハードウェアレジスタに格納されることは完全に可能です。ガベージコレクターはこれを知らないため、オブジェクトが到達不能であると見なして収集します。

この引数は、GCを圧縮するために2倍になります。ハードウェアペリフェラルが使用するオブジェクトへのメモリ内参照を維持するように注意していても、GCがオブジェクトを再配置したとき、ペリフェラル構成レジスタに含まれているポインタを更新する方法がわかりません。

したがって、今度はimmobile DMAバッファとGC管理オブジェクトの混合が必要になります。つまり、両方の欠点がすべてあります。

4
Ben Voigt

なぜなら、CとC++は、たとえば、組み込みシステムで1MBのメモリを搭載した16ビットプロセッサで実行することを目的とした比較的低レベルの言語であり、GCでメモリを浪費する余裕がなかったためです。

3
Petruza

C++とCにはガベージコレクターがあります。Cでこれがどのように機能するかはわかりませんが、C++では [〜#〜] rtti [〜#〜] を利用してオブジェクトグラフを動的に検出し、それを使用できます。ガベージコレクション。

私の知る限り、Javaガベージコレクターなしで書くことはできません。少し検索が行われました this

JavaとC/C++の主な違いは、C/C++では常に自由に選択できることですが、Javaでは、設計。

2
back2dos

これは、パフォーマンスと安全性のトレードオフです。

ガベージがJavaで収集される保証はないため、参照されていないオブジェクト(ガベージ)のスキャンも、未使用のオブジェクトを明示的に削除または解放するよりも時間がかかりますが、長時間スペースを使い果たしてしまう可能性があります。

もちろん、利点は、ポインタやメモリリークのない言語を構築できるため、正しいコードを生成する可能性が高くなることです。

時々、これらの議論にはわずかな「宗教的な」エッジが存在する可能性があります-警告してください!

2
adrianmcmenamin

以下は、GCのようなシステム言語で使用できなくなるGCの固有の問題のリストです。

  • GCは、オブジェクトを管理するコードのレベルよりも下で実行する必要があります。カーネルにはそのようなレベルはありません。

  • GCは時々マネージコードを停止する必要があります。それがあなたのカーネルにそれをしたとしたらどうなるかを考えてください。マシン上のすべての処理は、たとえばミリ秒停止しますが、GCは既存のすべてのメモリ割り当てをスキャンします。これは、厳密なリアルタイム要件の下で動作するシステムを作成するすべての試みを殺します。

  • GCは、ポインターと非ポインターを区別できる必要があります。つまり、存在するすべてのメモリオブジェクトを調べ、そのポインタが見つかるオフセットのリストを生成できる必要があります。

    この発見は完璧でなければなりません。GCは発見したすべてのポインタを追跡できる必要があります。誤検知を逆参照すると、クラッシュする可能性があります。偽陰性の発見に失敗した場合は、まだ使用中のオブジェクトが破壊される可能性があり、マネージコードがクラッシュするか、データが静かに破損します。

    これには、存在するすべてのオブジェクトに型情報が格納されていることが絶対に必要です。ただし、CとC++はどちらも、型情報を含まない古いデータオブジェクトを許可します。

  • GCは本質的に遅いビジネスです。 Javaで社会化されたプログラマはこれを認識しないかもしれませんが、プログラムがJavaに実装されていない場合、桁違いに速くなる可能性があります。そしてJava遅いのはGCです。これは、JavaのようなGCされた言語がスーパーコンピューティングで使用されないようにするものです。マシンの消費電力が年間100万ドルの場合、支払いをしたくないでしょう。ガベージコレクションの場合でも、その10%です。

CおよびC++は、考えられるすべてのユースケースをサポートするために作成された言語です。そして、ご覧のとおり、これらのユースケースの多くはガベージコレクションによって除外されています。したがって、これらの使用例をサポートするために、C/C++はガベージコレクションできません。