Javaオブジェクトが参照されなくなった直後に削除されないのはなぜですか?


77

Javaでは、オブジェクトに参照がなくなるとすぐに削除の対象になりますが、JVMはオブジェクトが実際に削除されるタイミングを決定します。Objective-Cの用語を使用する場合、すべてのJava参照は本質的に「強力」です。ただし、Objective-Cでは、オブジェクトに強参照がなくなった場合、オブジェクトはすぐに削除されます。なぜこれがJavaに当てはまらないのですか?


46
Javaオブジェクトが実際に削除されるタイミングは気する必要はありません。これは実装の詳細です。
バジルスタリンケビッチ

154
@BasileStarynkevitchシステム/プラットフォームがどのように機能するかを絶対に気にかけ、挑戦する必要があります。「どのように」「なぜ」という質問をすることは、優れたプログラマー(そして、より一般的な意味では、より賢い人)になるための最良の方法の1つです。
アルトゥールBiesiadowski

6
循環参照がある場合、Objective Cは何をしますか?私はそれが単にそれらを漏らしていると思いますか?
Mehrdad

45
@ArturBiesiadowksi:いいえ、Java仕様では、オブジェクトがいつ削除されるかはわかりません(同様に、R5RSの場合)。削除が発生しない場合は、Javaプログラム開発できます(おそらく、Java Hello Worldのような短命のプロセスの場合、実際には発生しません)。生きているオブジェクトのセット(またはメモリ消費)に関心があるかもしれませんが、これは別の話です。
バジルスタリンケビッチ

28
ある日、初心者がマスターに「割り当て問題の解決策がある。すべての割り当てに参照カウントを与え、ゼロに達したらオブジェクトを削除できる」と言った。マスターは私が解決策を持っている...「ある日は、初心者がマスターに言った、」答え
エリックリペット

回答:


79

まず、Javaには弱い参照と、ソフト参照と呼ばれる別のベストエフォートカテゴリがあります。弱い参照と強い参照は、参照カウントとガベージコレクションとはまったく別の問題です。

第二に、メモリ使用量のパターンがあり、スペースを犠牲にすることで、ガベージコレクションをより効率的にすることができます。たとえば、新しいオブジェクトは、古いオブジェクトよりも削除される可能性がはるかに高くなります。したがって、スイープの間に少し待つと、少数の生存者をより長期のストレージに移動しながら、新しい世代のメモリのほとんどを削除できます。その長期保存は、はるかに少ない頻度でスキャンできます。手動のメモリ管理または参照カウントを介した即時削除は、断片化を起こしやすい傾向があります。

これは、給料ごとに食料品の買い物に行くことと、一日に十分な食料を得るために毎日行くこととの違いのようなものです。1回の大きな旅行は、個々の小さな旅行よりもはるかに時間がかかりますが、全体的には時間とお金を節約できます。


58
プログラマーの妻が彼をスーパーに送ります。彼女は彼に言った、「パンを一Bu買って、もしあなたが卵を見つけたら一ダース掴みなさい」。プログラマーは、彼の腕の下にパンを一with入れて戻ってきます。
ニール

7
新世代のgc時間は一般にライブオブジェクトの量に比例するため、多くの場合、削除されたオブジェクトが増えるとコストがまったく支払われないことを言及することをお勧めします。削除サバイバースペースポインタを反転し、必要に応じて1つの大きなはmemset(それはGCの最後に行われるかtlabsの割り当て時に償却または現在のJVMにオブジェクト自体をされている場合わからない)でメモリ空間全体をゼロにするのと同じくらい簡単です
アルトゥールBiesiadowski

64
@Neilは13個のパンではないですか?
JAD

67
「通路7での1つのエラーによる」
-joeytwiddle

13
@JAD 13と言っていただろうが、ほとんどの人はそうなる傾向はない。;)
ニール

86

何かを適切に知ることはもはや参照されていないため、簡単ではありません。簡単にも近い。

相互に参照する2つのオブジェクトがある場合はどうなりますか?彼らは永遠に滞在しますか?この考え方を拡張して任意のデータ構造を解決すると、JVMやその他のガベージコレクターが、まだ必要なものと何ができるかを判断するためのはるかに洗練された方法を採用せざるを得ない理由がすぐにわかります。


7
または、可能な限り参照カウントを使用するPythonのアプローチを採用し、循環リークによってメモリリークが発生すると予想される場合はGCに頼ることもできます。GCに加えて再カウントできない理由がわかりませんか?
Mehrdad

27
@Mehrdad彼らはできました。しかし、おそらくそれは遅いでしょう。これを実装することを妨げるものは何もありませんが、HotspotまたはOpenJ9のGCに勝るものはありません。
ヨーゼフ

21
@ jpmc26は、使用されなくなったオブジェクトをすぐに削除すると、高負荷状態で削除される可能性が高くなり、負荷がさらに増加するためです。GCは、負荷が少ないときに実行できます。参照カウント自体は、すべての参照の小さなオーバーヘッドです。また、GCを使用すると、単一のオブジェクトを処理せずに、参照なしでメモリの大部分を破棄できることがよくあります。
ジョセフ

33
@Josef:適切な参照カウントも無料ではありません。参照カウントの更新にはアトミックなインクリメント/デクリメントが必要です。これ、特に最新のマルチコアアーキテクチャでは驚くほど高価です。CPythonでは、それほど問題ではありません(CPython自体は非常に遅く、GILはマルチスレッドパフォーマンスをシングルコアレベルに制限します)が、並列処理もサポートする高速言語では問題になる可能性があります。PyPyが参照カウントを完全になくし、GCを使用するだけではありません。
マッテオイタリア

10
@Mehrdad Javaの参照カウントGCを実装したら、他のGC実装よりもパフォーマンスが悪い場合を見つけるために喜んでテストします。
ジョセフ

45

私の知る限り、JVM仕様(英語で書かれています)では、オブジェクト(または値)を正確にいつ削除するかについて言及せず、それを実装に残しています(R5RSの場合も同様)。何らかの方法でガベージコレクタが必要または提案されますが、詳細は実装に任せます。また、Java仕様についても同様です。

プログラミング言語は、ソフトウェアの実装ではなく、(構文セマンティクスなどの)仕様であることに注意してください。Java(またはそのJVM)のような言語には多くの実装があります。その仕様は公開されており、ダウンロード可能(学習できるように)され、英語で書かれています。§2.5.3JVM仕様のヒープには、ガベージコレクターが記載されています。

オブジェクトのヒープストレージは、自動ストレージ管理システム(ガベージコレクター)によって回収されます。オブジェクトが明示的に割り当て解除されることはありません。Java仮想マシンは、特定のタイプの自動ストレージ管理システムを想定していません

(強調は私です。BTWファイナライズは、に記載されている§12.6のJava仕様の、およびメモリモデルがである§17.4のJava仕様の)

そのため(Javaでは)オブジェクトがいつ削除されるかを気する必要はありません。また、(それを無視する抽象化で推論することにより)発生しない場合はコーディングできます。もちろん、メモリ消費と生きているオブジェクトのセットに注意する必要がありますが、これは別の質問です。いくつかの単純なケース(「hello world」プログラムのような)では、割り当てられたメモリがかなり小さい(たとえば1ギガバイト未満)ことを証明することができます-または自分自身を納得させることができます。個々のオブジェクトの削除。多くの場合、生き物は(または到達可能なもの、これは生きているもののスーパーセット-推論するのが簡単です-)合理的な制限を超えることはありません(そして、GCに依存しますが、ガベージコレクションがいつどのように発生するかは気にしません)。スペースの複雑さについて読んでください。

Hello Worldのような短命のJavaプログラムを実行しているいくつかのJVM実装では、ガベージコレクターはまったくトリガーされず、削除は行われないと思います。AFAIU、そのような振る舞いは多数のJava仕様に準拠しています。

ほとんどのJVM実装は世代別のコピー技術を使用します(少なくともほとんどのJavaオブジェクトでは、ファイナライズまたはウィークリファレンスを使用しません;ファイナライズは短時間で発生することが保証されておらず、延期される可能性があるため、コードがすべきではない便利な機能です(個々のオブジェクトを削除するという概念が意味をなさない)(多くのオブジェクトのメモリゾーンを含む多くのメモリブロック、おそらく一度に数メガバイト)が一度に解放されるため)

JVM仕様で各オブジェクトをできるだけ正確に削除する必要がある場合(または単にオブジェクトの削除により多くの制約を課す場合)、効率的な世代別GCテクニックは禁止され、JavaおよびJVMの設計者はそれを避けるのが賢明です。

ところで、オブジェクトを決して削除せず、メモリを解放しないナイーブJVMは、仕様(精神ではなく文字)に準拠している可能性があり、実際にハローワールドを実際に実行できる可能性があります(ほとんどのことに注意してください)小さくて短命なJavaプログラムは、おそらく数ギガバイト以上のメモリを割り当てません。もちろん、このようなJVMは言及する価値はなく、単なるおもちゃです(このmalloc Cの実装のように)。詳細については、Epsilon NoOp GCを参照してください。実際のJVMは非常に複雑なソフトウェアであり、いくつかのガベージコレクション技術が混在しています。

また、JavaはJVMとは異なり、JVMなしで実行するJava実装があります(たとえば、事前の Javaコンパイラー、Androidランタイム)。では、いくつかの例(主に学術的なもの)、あなたが想像するかもしれない(そう、「コンパイル時のガベージコレクション」技術と呼ばれる)は、Javaプログラムが(実行時に割り当てたり削除しないことを例えばので、最適化コンパイラは、のみを使用してくれてきました呼び出しスタック自動変数)。

Javaオブジェクトが参照されなくなった直後に削除されないのはなぜですか?

JavaとJVMの仕様はそれを必要としないためです。


詳細については、GCハンドブック(およびJVM仕様)を参照してください。オブジェクトの生存(または将来の計算に役立つ)は、プログラム全体(非モジュラー)のプロパティであることに注意してください。

Objective-Cは、メモリ管理への参照カウントアプローチを好みます。また、落とし穴もあります(たとえば、Objective-C プログラマーは、弱い参照を明示することで循環参照に注意する必要がありますが、JVMは実際にはJavaプログラマーの注意を必要とせずに循環参照をうまく処理します)。

プログラミングとプログラミング言語の設計にはSilver BulletありませんHaltting Problemに注意してください;有用な生きているオブジェクトであることは、一般的に決定できません)。

また、SICPプログラミング言語プラグマティクスドラゴンブックLisp In Small PiecesおよびOperating Systems:Three Easy Piecesも読んでください。Javaに関するものではありませんが、心を開き、JVMが何をすべきか、コンピューターで(他の部分と)実際に動作する方法を理解するのに役立ちます。また、既存のオープンソース JVM実装の複雑なソースコード(数百万のソースコード行があるOpenJDKなど)の研究に何ヶ月(または数年)費やすこともできます。


20
「オブジェクトを決して削除せず、メモリを解放しない単純なJVMが仕様に準拠している可能性があります」最も確かに仕様に準拠しています。Java 11は、特に非常に短命のプログラムのために、ノーオペレーションガベージコレクターを実際に追加しています。
マイケル

6
「オブジェクトがいつ削除されるかは気にする必要はありません」反対。たとえば、RAIIは実行可能なパターンではなく、finalizeリソース管理(ファイルハンドル、db接続、gpuリソースなど)に依存できないことを知っておく必要があります。
アレクサンダー

4
@Michael使用済みメモリの上限があるバッチ処理に最適です。OSは「このプログラムで使用されていたすべてのメモリがなくなった」と言うことができます。結局のところ、これはかなり高速です。実際、Cの多くのプログラムは、特に初期のUnixの世界では、そのように書かれていました。パスカルには非常に恐ろしい「事前に保存されたチェックポイントへのスタック/ヒープポインタのリセット」があり、まったく同じことを行うことができましたが、マーク、サブタスクの開始、リセットを行いました。
ルアーン

6
@Alexanderは一般にC ++(および意図的に派生するいくつかの言語)の外部で、RAIIがファイナライザーのみに基づいて機能することを前提とするアンチパターンは、警告され、明示的なリソース制御ブロックに置き換えられるべきです。GCの全体的なポイントは、結局、ライフタイムとリソースが切り離されているということです。
ルーシェンコ

3
@Leushenko私は、「ライフタイムとリソースが切り離されている」ことはGCの「全体のポイント」であることに強く反対します。GCの主なポイントである、簡単で安全なメモリ管理に対して支払う負の価格です。「ファイナライザーのみに基づいてRAIIが機能すると仮定するのはアンチパターンです」Javaでは?おそらく。しかし、CPython、Rust、Swift、またはObjective Cではそうではありません。「明示的なリソース制御ブロックに対して警告され、置き換えられました」いいえ、これらは厳密に制限されています。RAIIを介してリソースを管理するオブジェクトは、スコープ付きライフを渡すためのハンドルを提供します。try-with-resourceブロックは、単一のスコープに制限されています。
アレクサンダー

23

Objective-Cの用語を使用する場合、すべてのJava参照は本質的に「強力」です。

これは正しくありません-Javaには弱参照とソフト参照の両方がありますが、これらは言語キーワードとしてではなくオブジェクトレベルで実装されます。

Objective-Cでは、オブジェクトに強参照がなくなった場合、オブジェクトはすぐに削除されます。

これも必ずしも正しいとは限りません。ObjectiveCの一部のバージョンでは、実際に世代別のガベージコレクターが使用されていました。他のバージョンにはガベージコレクションがまったくありませんでした。

Objective Cの新しいバージョンでは、トレースベースのGCではなく自動参照カウント(ARC)を使用しているため、参照カウントが0になるとオブジェクトが「削除」されることがよくあります。ただし、JVM実装も準拠しており、まさにこの方法で動作する可能性があることに注意してください(つまり、準拠していて、GCがまったくない場合もあります)。

では、ほとんどのJVM実装がこれを行わず、代わりにトレースベースのGCアルゴリズムを使用するのはなぜですか?

簡単に言えば、ARCは最初に思われるほど理想的ではありません。

  • 参照がコピー、変更、またはスコープ外になるたびにカウンターをインクリメントまたはデクリメントする必要があり、これによりパフォーマンスのオーバーヘッドが明らかになります。
  • ARCは循環参照を簡単にクリアできません。それらはすべて相互参照を持っているため、参照カウントがゼロになることはありません。

ARCにはもちろん利点があります-ARCの実装と収集は簡単です しかし、上記の欠点は、とりわけ、JVM実装の大半が世代ベースのトレースベースのGCを使用する理由です。


1
おもしろいことに、Appleは実際に他のGC(特に世代別のGC)を大幅に上回ることがわかったため、ARCに切り替えました。公平を期すために、これはメモリに制約のあるプラットフォーム(iPhone)でほとんど当てはまります。しかし、世代別(およびその他の非決定論的)GCは最初のようにユートピア的ではないということで、「ARCは最初に思えるほどユートピア的ではない」というあなたの声明に反論します。大半のシナリオ。
コンラッドルドルフ

3
@KonradRudolphは、むしろ決定論的破壊のファンでもありますが、「大多数のシナリオでより良いオプション」が成り立つとは思いません。レイテンシやメモリが平均スループットよりも重要な場合、特にロジックが合理的に単純な場合、これは確かに優れたオプションです。しかし、多くの循環参照などを必要とし、高速な平均操作を必要とする複雑なアプリケーションはそれほど多くないようですが、実際にはレイテンシを気にせず、十分なメモリを使用できます。これらの場合、ARCが良いアイデアかどうかは疑わしいです。
左辺り

1
@leftaroundabout「ほとんどのシナリオ」では、スループットもメモリプレッシャーもボトルネックではないため、どちらの方法でもかまいません。あなたの例は1つの特定のシナリオです。確かに、それは極端に珍しいことではありませんが、ARCがより適している他のシナリオよりも一般的であると主張する限り、私は行きません。さらに、ARC サイクルをうまく処理できます。プログラマーによる単純で手動の介入が必要です。これにより、理想的ではなくなりますが、ほとんどの場合、問題を解決することはできません。決定論的なファイナライズは、あなたがふりをするよりもはるかに重要な特性であると私は考えます。
コンラッドルドルフ

3
@KonradRudolph ARCがプログラマーによる単純な手動介入を必要とする場合、サイクルを処理しません。二重リンクリストを頻繁に使用し始めると、ARCは手動のメモリ割り当てに移ります。大きな任意のグラフがある場合、ARCはガベージコレクタの作成を強制します。GCの議論は、破壊を必要とするリソースはメモリサブシステムの仕事ではないということであり、それらの比較的少数を追跡するために、プログラマーによるいくつかの簡単な手動介入によって決定論的に確定する必要があります。
-prosfilaes

2
@KonradRudolph ARCおよびサイクルは、それらが手動で処理されない場合、基本的にメモリリークにつながります。十分に複雑なシステムでは、たとえば、マップに格納されているオブジェクトがそのマップへの参照を格納している場合、そのマップを作成および破壊するコードのセクションを担当しないプログラマーが変更できる場合、大きなリークが発生する可能性があります。大きな任意のグラフは、内部ポインタが強くないという意味ではなく、リンクされたアイテムが消えてもいいという意味です。いくつかのメモリリークに対処することは、手動でファイルを閉じるよりも問題ではないかどうかはわかりませんが、それは現実です。
-prosfilaes

5

Javaは、オブジェクトがガベージコレクションを処理する方法を選択する自由を実装に与えるため、オブジェクトが収集されるタイミングを正確に指定しません。

ガベージコレクションメカニズムにはさまざまなものがありますが、オブジェクトをすぐに収集できることを保証するものは、ほぼ完全に参照カウントに基づいています(この傾向を破るアルゴリズムは知りません)。参照カウントは強力なツールですが、参照カウントを維持するにはコストがかかります。シングルスレッドコードでは、それはインクリメントとデクリメントに過ぎないため、ポインターを割り当てると、参照カウントコードの場合と比較して非参照カウントコードの場合の3倍のコストがかかります(コンパイラーがすべてをマシンに焼き付けることができる場合)コード)。

マルチスレッドコードでは、コストが高くなります。アトミックなインクリメント/デクリメントまたはロックのいずれかを呼び出しますが、どちらも高価になる可能性があります。最新のプロセッサーでは、アトミック操作は単純なレジスター操作よりも20倍程度高価になる場合があります(プロセッサーごとに明らかに異なります)。これにより、コストが増加する可能性があります。

そのため、これにより、いくつかのモデルのトレードオフを考慮することができます。

  • Objective-Cは、ARC-自動化された参照カウントに焦点を当てています。彼らのアプローチは、すべてに対して参照カウントを使用することです。(私が知っている)サイクル検出はないため、プログラマーは、サイクルの発生を防ぐことが期待されており、開発時間のコストがかかります。彼らの理論では、ポインタはそれほど頻繁には割り当てられず、コンパイラは参照カウントをインクリメント/デクリメントしてもオブジェクトが死なない状況を特定し、それらのインクリメント/デクリメントを完全に排除できます。したがって、参照カウントのコストを最小限に抑えます。

  • CPythonはハイブリッドメカニズムを使用します。参照カウントを使用しますが、サイクルを識別して解放するガベージコレクタもあります。これは、両方のアプローチの犠牲を払って、両方の世界の利点を提供します。CPythonは参照カウントサイクルを検出するためにブックキーピングを行います。CPythonはこれを2つの方法で回避します。第一に、CPythonは実際には完全にマルチスレッド化されていないということです。マルチスレッドを制限するGILとして知られるロックがあります。これは、CPythonがアトミックなものではなく通常のインクリメント/デクリメントを使用できることを意味します。これははるかに高速です。CPythonも解釈されます。つまり、変数への代入などの操作は、1つだけではなく、既にいくつかの命令を取ります。 veはすでにこの費用を支払っています。

  • Javaは、参照カウントシステムをまったく保証しないというアプローチを取り下げます。実際、仕様では、自動ストレージ管理システムがあること以外、オブジェクトの管理方法については何も言及していません。ただし、この仕様は、これがサイクルを処理する方法でガベージコレクションされるという仮定を強く示唆しています。オブジェクトの有効期限を指定しないことにより、javaは、時間の増分/減分を無駄にしないコレクターを自由に使用できます。確かに、世代別ガベージコレクターなどの賢いアルゴリズムは、再生中のデータを見なくても多くの単純なケースを処理することさえできます(参照されているデータのみを見る必要があります)。

したがって、これら3つはそれぞれトレードオフを行う必要がありました。どのトレードオフが最適かは、言語の使用方法の性質に大きく依存します。


4

finalizeJavaのGCに便乗しましたが、コアのガベージコレクションは死んだオブジェクトではなく、生きているオブジェクトに関心があります。一部のGCシステム(Javaの一部の実装を含む可能性があります)では、オブジェクトを表すビットの集合と、何にも使用されないストレージの集合を区別する唯一のものは、前者への参照の存在です。ファイナライザを持つオブジェクトは特別なリストに追加されますが、他のオブジェクトは、ユーザーコードに保持されている参照を除き、ストレージがオブジェクトに関連付けられているというユニバースのどこにも存在しない場合があります。このような最後の参照が上書きされると、メモリ内のビットパターンは、宇宙の何かがそれを認識しているかどうかに関係なく、オブジェクトとしてすぐに認識できなくなります。

ガベージコレクションの目的は、参照が存在しないオブジェクトを破棄することではなく、次の3つのことを達成することです。

  1. 強到達可能な参照が関連付けられていないオブジェクトを識別する弱参照を無効にします。

  2. ファイナライザを使用してシステムのオブジェクトのリストを検索し、それらに関連付けられた強力に到達可能な参照がないオブジェクトがあるかどうかを確認します。

  3. オブジェクトによって使用されていないストレージの領域を特定して統合します。

GCの主な目標は3番目であり、GCを実行するまでの待機時間が長いほど、統合の機会が増える可能性が高いことに注意してください。ストレージをすぐに使用する場合は#3を行うのが理にかなっていますが、そうでない場合はそれを延期する方が理にかなっています。


5
実際、gcには1つの目標しかありません。無限のメモリをシミュレートすることです。目標として指定したものはすべて、抽象化の不完全さまたは実装の詳細です。
デュプリケータ

@Deduplicator:弱い参照は、GCの支援なしでは達成できない有用なセマンティクスを提供します。
-supercat

確かに、弱い参照には有用なセマンティクスがあります。しかし、シミュレーションが改善された場合、これらのセマンティクスが必要になりますか?
デュプリケータ

@Deduplicator:はい。更新が列挙と相互作用する方法を定義するコレクションを検討してください。このようなコレクションは、ライブ列挙子への弱い参照を保持する必要がある場合があります。無制限のメモリシステムでは、繰り返し繰り返されるコレクションは、関心のある列挙子のリストを無限に成長させます。そのリストに必要なメモリは問題になりませんが、リストを繰り返すのに必要な時間はシステムのパフォーマンスを低下させます。GCを追加すると、O(N)アルゴリズムとO(N ^ 2)アルゴリズムの違いがわかります。
-supercat

2
リストに追加して使用時に列挙子を探すのではなく、列挙子に通知するのはなぜですか?そして、メモリのプレッシャーに依存するのではなく、タイムリーに処理されているガーベッジに依存するプログラムは、それが動くとしても、とにかく罪の状態で生きています。
デュプリケータ

4

あなたの質問の言い換えと一般化を提案させてください。

JavaがGCプロセスについて強力な保証をしないのはなぜですか?

それを念頭に置いて、ここで回答をすばやくスクロールしてください。これまでに7つあり(これは数えていません)、コメントスレッドはかなりあります。

それがあなたの答えです。

GCは難しいです。多くの考慮事項、多くの異なるトレードオフ、そして最終的には非常に異なるアプローチがたくさんあります。これらのアプローチのいくつかは、オブジェクトが不要になるとすぐにGCを実行できるようにします。他の人はしません。契約を緩く保つことにより、Javaは実装者により多くのオプションを提供します。

もちろん、その決定にもトレードオフがあります。契約を緩く保つことにより、Java *はほとんどプログラマーがデストラクタに依存する能力を奪います。これは特にC ++プログラマが見逃しがちなものです([要出典];))。したがって、取るに足らないトレードオフではありません。私はその特定のメタ決定についての議論を見ていませんが、おそらく、Javaの人々は、GCオプションを増やすことの利点は、オブジェクトがいつ破壊されるかをプログラマに正確に伝えることができるという利点を上回ると判断したと思われます。


* finalize方法はありますが、この答えの範囲外のさまざまな理由から、それに頼るのは難しく、良い考えではありません。


3

開発者が明示的なコードを記述せずにメモリを処理するには、ガベージコレクションと参照カウントの2つの異なる戦略があります。

ガベージコレクションには、開発者が愚かなことをしない限り「機能する」という利点があります。参照カウントを使用すると、参照サイクルを設定できます。つまり、「機能」しますが、開発者は賢明な場合があります。ガベージコレクションにはプラスになります。

参照カウントでは、参照カウントがゼロになるとオブジェクトはすぐに消えます。これは、参照カウントの利点です。

速度面では、ガベージコレクションのファンを信じる場合はガベージコレクションが速くなり、参照カウントのファンを信じる場合は参照カウントが速くなります。

同じ目標を達成するための2つの異なる方法であり、Javaが1つの方法を選択し、Objective-Cが別の方法を選択しました(さらに、多くのコンパイラーサポートを追加して、手間のかかるものから開発者にとってほとんど役に立たないものに変更しました)。

Javaをガベージコレクションから参照カウントに変更することは、多くのコード変更が必要になるため、大きな仕事です。

理論的には、Javaはガベージコレクションと参照カウントの混合を実装できます。参照カウントが0の場合、オブジェクトは到達不能ですが、必ずしもその逆ではありません。そのため、参照カウントを保持し、参照カウントがゼロのときにオブジェクトを削除することができます(そして、ガベージコレクションを時々実行して、到達不能な参照サイクル内でオブジェクトをキャッチします)。ガベージコレクションに参照カウントを追加するのは悪い考えだと思う人と、参照カウントにガベージコレクションを追加するのは悪い考えだと思う人とでは、世界は50対50に分かれていると思います。したがって、これは起こりません。

そのため、Java 、参照カウントがゼロになるとすぐにオブジェクトを削除し、到達不能なサイクル内でオブジェクトを削除できます。しかし、それは設計上の決定であり、Javaはそれに対して決定しました。


参照カウントを使用すると、プログラマがサイクルを処理するため、ファイナライズは簡単です。gcでは、サイクルは簡単ですが、プログラマはファイナライズに注意する必要があります。
デュプリケータ

@Deduplicator Javaでは、ファイナライズされるオブジェクトへの強い参照を作成することもできます... Objective-CおよびSwiftでは、参照カウントがゼロになると、オブジェクト消えます(無限ループをdealloc / deistに入れない限り)。
gnasher729

ただ、愚かなスペルチェッカーdeistとdeinit交換...気づい
gnasher729を

1
ほとんどのプログラマは、自動スペル修正を嫌う理由があります... ;-)
デュプリケータ

lol ...参照カウントをガベージコレクションに追加するのは悪い考えだと思う人と、参照カウントにガベージコレクションを追加するのは悪い考えだと思う人と、ので、ガベージコレクションが到着するまでの日数を数え続けることトンが既に臭い再び取得している ...
leftaroundabout

1

私が言及する価値があると思うもう1つのアイデアは、このようなものを検討する少なくとも1つのJVM(azul)があるということですがそれは、基本的にvmスレッドが常に参照をチェックしてそれらを削除しようとする並列gcを実装していることであり、これはあなたが話していることとはまったく異なりません。基本的には、ヒープを常に見回し、参照されていないメモリを回収しようとします。これにより、非常にわずかなパフォーマンスコストが発生しますが、本質的にゼロまたは非常に短いGC時間につながります。(つまり、常に拡大するヒープサイズがシステムRAMを超えない限り、Azulは混乱し、ドラゴンが存在します)

TLDR JVMには、そのようなものが存在します。これは特別なjvmであり、他のエンジニアリング上の妥協のような欠点があります。

免責事項:前の仕事で使用したばかりのAzulとは関係がありません。


1

持続スループットの最大化またはGCレイテンシの最小化は動的な緊張状態にあります。これはおそらく、GCがすぐに発生しない最も一般的な理由です。911緊急アプリのような一部のシステムでは、特定の遅延しきい値を満たしていない場合、サイトのフェールオーバープロセスのトリガーを開始できます。銀行や裁定サイトのような他のサイトでは、スループットを最大化することがはるかに重要です。


0

速度

このすべてが行われている理由は、最終的には速度のためです。プロセッサが無限に高速である場合、または(実用的には)1秒あたり1,000,000,000,000,000,000,000,000,000,000,000操作に近い場合、参照解除されたオブジェクトが削除されていることを確認するなど、非常に長く複雑な処理が各演算子間で発生する可能性があります。現在、1秒あたりの操作数は真実ではなく、他のほとんどの回答が説明しているように、これを理解するのは実際には複雑でリソース集約的であるため、ガベージコレクションが存在するため、プログラムは、迅速な方法。


まあ、私はそれよりも余分なサイクルを使い果たすより興味深い方法を見つけると確信しています。
デュプリケータ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.