誰かがARCの仕組みを簡単に説明できますか?ガベージコレクションとは異なることは知っていますが、どのように機能するのかを正確に知りたいだけでした。
また、ARCがパフォーマンスを妨げることなくGCの機能を実行する場合、なぜJavaがGCを使用するのですか?なぜARCも使用しないのですか?
Objective-Cに来るすべての新しい開発者は、オブジェクトを保持、リリース、および自動リリースするタイミングの厳格なルールを学習する必要があります。これらのルールは、メソッドから返されるオブジェクトの保持カウントを暗示する命名規則も指定します。 Objective-Cのメモリ管理は、これらのルールを念頭に置いて一貫して適用すると、2番目の性質になりますが、最も経験豊富なCocoa開発者でさえ、時折スリップします。
Clang Static Analyzerを使用して、LLVM開発者は、これらのルールが十分に信頼性が高く、コードがたどるパス内のメモリリークとオーバーリリースを指摘するツールを構築できることに気付きました。
自動参照カウント (ARC)は次の論理ステップです。コンパイラがオブジェクトを保持および解放すべき場所を認識できる場合、そのコードを挿入してみませんか?厳格で反復的なタスクは、コンパイラとその仲間が得意とするものです。人間は物事を忘れて間違いを犯しますが、コンピューターはずっと一貫しています。
ただし、これらのプラットフォームでのメモリ管理について心配する必要はありません。私の答え here で注意すべき(循環を保持する)主要な問題について説明します。これは、弱いポインターをマークするためにあなたの側で少し考える必要があるかもしれません。ただし、ARCで得られるものと比較すると、それはわずかです。
手動のメモリ管理とガベージコレクションと比較すると、ARCは、ガベージコレクション環境で見られる停止およびノコギリメモリプロファイルを持たずに、保持/解放コードを記述する必要性を排除することにより、両方の長所を提供します。ガベージコレクションがこれより優れている唯一の利点については、保持サイクルを処理する能力と、アトミックプロパティの割り当てが安価であるという事実です( () )。私は既存のMac GCコードをすべてARC実装に置き換えていることを知っています。
これを他の言語に拡張できるかどうかについては、Objective-Cの参照カウントシステムに関連しているようです。これをJavaまたは他の言語に適用するのは難しいかもしれませんが、低レベルのコンパイラの詳細については、そこに明確なステートメントを作成するのに十分な知識がありません。 AppleがLLVMでこの努力を推進していることを考えると、他の当事者がこれに独自の重要なリソースをコミットしない限り、Objective-Cが最初になります。
この発表はWWDCの開発者に衝撃を与えたので、人々はこのようなことができることを知りませんでした。時間の経過とともに他のプラットフォームに表示される可能性がありますが、現時点ではLLVMとObjective-C専用です。
ARCは、保持/リリースをいつ呼び出すかをコンパイラーが判断して、古い保持/リリース(MRC)を再生するだけです。 GCシステムよりもパフォーマンスが高く、ピーク時のメモリ使用量が少なく、予測可能なパフォーマンスが得られる傾向があります。
一方、ARC(またはMRC)では一部のタイプのデータ構造は使用できませんが、GCはそれらを処理できます。
例として、nodeという名前のクラスがあり、nodeには子のNSArrayがあり、GCで「機能する」親への単一の参照があるとします。 ARC(および手動参照カウント)には問題があります。特定のノードは、その子からも親からも参照されます。
好む:
A -> [B1, B2, B3]
B1 -> A, B2 -> A, B3 -> A
Aを使用している間はすべて問題ありません(たとえば、ローカル変数経由)。
それ(およびB1/B2/B3)を完了すると、GCシステムは最終的に、スタックおよびCPUレジスタから始めて見つけることができるすべてのものを調べることにします。 A、B1、B2、B3は検出されないため、それらをファイナライズし、メモリを他のオブジェクトにリサイクルします。
ARCまたはMRCを使用し、Aで終了すると、refcountは3(B1、B2、およびB3はすべて参照)になり、B1/B2/B3はすべて1の参照カウントになります(AのNSArrayは、各)。そのため、これらのオブジェクトはすべて、何も使用できない場合でもライブのままです。
一般的な解決策は、これらの参照の1つを弱くする必要がある(参照カウントに寄与しない)ことを決定することです。これは、たとえばA経由でのみB1/B2/B3を参照する場合など、一部の使用パターンで機能します。ただし、他のパターンでは失敗します。たとえば、B1を保持することがあり、親ポインターを介して上昇してAを見つけることが予想される場合、B1のみを保持する場合、Aが蒸発し、B2およびB3を取ることができますそれと。
これは問題にならない場合もありますが、データの複雑な構造を扱う非常に便利で自然な方法は、ARC/MRCで使用するのが非常に困難です。
そのため、ARCはGCが対象とする同じ種類の問題を対象としています。ただし、ARCはGCよりも制限された使用パターンのセットで動作するため、GC言語(Javaなど)を使用してARCなどを移植すると、一部のプログラムは動作しなくなります(または少なくとも大量の放棄されたメモリが生成されます) 、深刻なスワッピングの問題を引き起こしたり、メモリまたはスワップ領域が不足する可能性があります)。
また、ARCはパフォーマンス(または予測可能性)を重視し、GCは汎用ソリューションであることを重視しています。その結果、GCはARCよりも予測可能なCPU /メモリ要求が少なく、(通常)パフォーマンスが低下しますが、あらゆる使用パターンを処理できます。 ARCは、多くの一般的な使用パターンに対してはるかに優れた機能を発揮しますが、いくつかの(有効な!)使用パターンに対しては機能しなくなります。
マジック
しかし、より具体的には、ARCはコードで行うことを正確に実行することで機能します(特定の小さな違いはあります)。 ARCは、ランタイムでありパフォーマンスに悪影響を与えるGCとは異なり、コンパイル時のテクノロジーです。 ARCは、オブジェクトへの参照を追跡し、通常の規則に従ってretain/release/autoreleaseメソッドを合成します。このため、ARCは、単に慣例のために自動解放プールにそれらを投げ込むのではなく、不要になったものをすぐに解放することもできます。
その他の改善点には、弱参照のゼロ化、ヒープへのブロックの自動コピー、ボード全体の高速化(自動解放プールで6倍!)が含まれます。
これがどのように機能するかについての詳細な議論は、ARCの LLVM Docs にあります。
ガベージコレクションとは大きく異なります。別の行のオブジェクトをリークしている可能性があることを示す警告を見ましたか?これらのステートメントは、オブジェクトをどの行に割り当てたかを示します。これはさらに一歩進んだもので、ほとんどの場合、ほとんどのプログラマーよりも適切な位置にretain
/release
ステートメントを挿入できるようになりました。時折、保持されたオブジェクトの奇妙なインスタンスがあり、それを手助けする必要があります。
ARCは、オブジェクトの自動メモリ管理を提供するコンパイラ機能です。
retain, release
およびautorelease
をいつ使用するかを覚えておく代わりに、ARCはオブジェクトの有効期間要件を評価し、コンパイル時に適切なメモリ管理呼び出しを自動的に挿入します。コンパイラーは、適切なdeallocメソッドも生成します。
コンパイラーはコンパイル時に必要なretain/release
呼び出しを挿入しますが、これらの呼び出しは他のコードと同様に実行時に実行されます。
次の図は、ARCがどのように機能するかをよりよく理解するのに役立ちます。
IOS開発の初心者で、Objective Cの実務経験がない人。メモリ管理のより良い理解については、Appleのドキュメント Advanced Memory Management Programming Guide を参照してください。
Apple開発者ドキュメントで非常によく説明されています。読み取り "ARCの仕組み"
インスタンスがまだ必要なときに消えないように、ARCは各クラスインスタンスを現在参照しているプロパティ、定数、変数の数を追跡します。インスタンスへのアクティブな参照が少なくとも1つ存在する限り、ARCはインスタンスの割り当てを解除しません。
インスタンスがまだ必要なときに消えないように、ARCは各クラスインスタンスを現在参照しているプロパティ、定数、変数の数を追跡します。インスタンスへのアクティブな参照が少なくとも1つ存在する限り、ARCはインスタンスの割り当てを解除しません。
差分を知るにはガベージコレクションとARCの間:読み取り this