新しい自動参照カウントメカニズムはどのように機能しますか?


206

誰かがARCのしくみを簡単に説明できますか?ガベージコレクションとは違うことは知っていますが、どういう仕組みになっているのか正確に疑問に思っていました。

また、ARCがパフォーマンスを妨げることなくGCを実行する場合、JavaはなぜGCを使用するのでしょうか。なぜARCも使用しないのですか?


2
これはあなたにそれについてすべてを教えてくれます:http : //clang.llvm.org/docs/AutomaticReferenceCounting.htmlそれがXcodeとiOS 5でどのように実装されているかはNDAの下にあります。
Morten Fast

14
@mbehan悪いアドバイスです。ログインしたくないし、iOS開発センターのアカウントさえ持っていませんが、それでもARCについて知りたいです。
Andres F.

1
ARCはGCが行うすべてのことを行うわけではありません。強い参照と弱い参照のセマンティクスを明示的に操作する必要があり、それらが正しくないとメモリをリークします。私の経験では、Objective-Cでブロックを使用する場合、これは最初はトリッキーです。また、トリックを知った後でも、ブロックの多くの使用法に関する厄介な(IMO)ボイラープレートコードが残っています。強い/弱い参照を忘れる方が便利です。さらに、GCはARC wrtよりもいくらか優れたパフォーマンスを発揮します。CPU、ただしより多くのメモリが必要です。大量のメモリがある場合は、明示的なメモリ管理よりも高速です。
TaylanUB 2013

@TaylanUB:「より多くのメモリが必要」。多くの人がそう言っていますが、信じられないほどです。
Jon Harrop、2014年

2
@JonHarrop:正直に言うと、なぜ私がそれを言ったのか覚えていません。:-)その間、私はそのような包括的なステートメントがおそらくすべて価値がないほど多くの異なるGC戦略があることに気づきました。私は彼からのハンス・ベームを暗唱してみましょうメモリ割り当て神話とハーフ真実「なぜ、このエリアはので、怪しげな民俗知恵を起こしやすいのですか?」
TaylanUB 2014年

回答:


244

Objective-Cに参加するすべての新しい開発者は、オブジェクトを保持、解放、および自動解放するときの厳格なルールを学ぶ必要があります。これらのルールは、メソッドから返されたオブジェクトの保持カウントを意味する命名規則も指定し​​ています。Objective-Cでのメモリ管理は、これらのルールを真摯に受け止めて一貫して適用すると第2の性質になりますが、経験豊富なCocoa開発者でさえ時々失敗します。

Clang Static Analyzerを使用して、LLVM開発者は、これらのルールが十分に信頼できるため、コードがたどるパス内のメモリリークとオーバーリリースを指摘するツールを構築できることに気付きました。

自動参照カウント(ARC)は次の論理的なステップです。オブジェクトを保持および解放する場所をコンパイラーが認識できる場合は、そのコードを挿入してはどうですか。厳格で反復的なタスクは、コンパイラとその兄弟が得意とするものです。人間は物事を忘れて間違いを犯しますが、コンピュータははるかに一貫しています。

ただし、これらのプラットフォームでのメモリ管理について心配する必要が完全になくなるわけではありません。私はここで私の答え(サイクルを維持する)に注意する主要な問題について説明します。これは、弱いポインタをマークするためにあなたの側で少し考える必要があるかもしれません。ただし、ARCで得られるものと比較すると、それはマイナーです。

手動のメモリ管理やガベージコレクションと比較すると、ARCは、保持/解放コードを記述する必要をなくし、ガベージコレクション環境で見られる停止および鋸歯状のメモリプロファイルがないため、両方の利点を提供します。ガベージコレクションがこれより優れている唯一の利点は、保持サイクルを処理できることと、アトミックプロパティの割り当てが安価であることです(ここで説明します)。既存のMac GCコードをすべてARC実装に置き換えていることを知っています。

これを他の言語に拡張できるかどうかについては、Objective-Cの参照カウントシステムを対象としています。これをJavaや他の言語に適用するのは難しいかもしれませんが、低レベルコンパイラの詳細について十分な知識がないので、そこに決定的な声明を出すことはできません。アップルがLLVMでこの取り組みを推進している企業であることを考えると、他の当事者が独自の重要なリソースをこれにコミットしない限り、Objective-Cが最初になります。

WWDCでこのショックを受けた開発者が発表されたので、このようなことができることを人々は知らなかった。時間の経過とともに他のプラットフォームにも表示される可能性がありますが、現時点ではLLVMとObjective-Cにのみ使用されます。


56
強調:私はこれでメモリ管理の心配から完全に解放されるわけではありません
bshirley '07 / 07/14

6
ARCは本当にイノベーションなのでしょうか?あなたの答えから、ARCはObjective-Cで初めて使用された新しい概念であると結論します(間違っている場合は修正してください)。正直なところ、私はObjective-Cの開発者ではなく、ARCについてもよく知りませんが、Boost Shared Pointers(boost.orgを参照)はまったく同じではありませんか?そうでない場合、違いは何ですか?
theDmi

2
@DMM-(Boostのように)オーバーロードされた演算子に依存するのではなく、これはコンパイラーレベルのプロセスであり、言語全体に拡張されます。特に、これにより、手動で参照カウントされたアプリケーションをARCに簡単に変換できます。Boostは、ローカル変数をARCとは異なる方法で処理することもできます。ARCは、ローカル変数が使用されなくなった時点でその時点で解放できることを認識しています。Boostを使用しても、変数を処理するように指定する必要があると私は信じています。
ブラッド・ラーソン

6
Delphiは、「これは新しいのか」という質問に答えるために、10年以上にわたって文字列、配列、およびインターフェイス(COMサポート用)の自動参照カウントを行ってきました。私はそれが本当にgc化された環境と「すべて手動で行う」環境との間の素晴らしい妥協であることに同意します。私はそれがObjCとLLVMにあることを嬉しく思います(そのため、他の言語もそれを利用できます)。
davidmw 2012年

2
@theDmi:「ARCは本当にイノベーションですか?」自動参照カウントは1960年に発明され、PythonやMathematicaなどの多くの言語で使用されています。非常に遅く、サイクルがリークするため、JVMまたはCLRでは使用されません。
Jon Harrop、2014年

25

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つの参照を保持します各)。したがって、これらのオブジェクトはすべて使用できませんが、ライブのままです。

一般的な解決策は、これらの参照の1つを弱くする必要がある(参照カウントに寄与しない)ことを決定することです。これは、A経由でのみB1 / B2 / B3を参照する場合など、一部の使用パターンで機能します。ただし、他のパターンでは失敗します。たとえば、B1を保持することがあり、親ポインタを介して上に戻るとAが見つかると予想します。弱い参照では、B1を保持するだけの場合、Aは蒸発して(通常は)B2とB3をとることができます。それと。

これが問題にならない場合もありますが、データの複雑な構造を操作する非常に便利で自然な方法は、ARC / MRCで使用するのが非常に困難です。

したがって、ARCはGCが対象とする同じ種類の問題を対象としています。ただし、ARCはGCよりも限られた使用パターンのセットで動作するため、GC言語(Javaなど)を使用してARCのようなものをその上に移植すると、一部のプログラムが動作しなくなります(または少なくとも大量の破棄されたメモリが生成されます) 、および重大なスワッピングの問題を引き起こすか、メモリまたはスワップ領域が不足する可能性があります)。

また、ARCはパフォーマンス(または予測可能性)を優先し、GCは一般的なソリューションであることを優先しているとも言えます。その結果、GCは予測可能なCPU /メモリ要求が少なく、ARCよりも(通常は)パフォーマンスが低くなりますが、あらゆる使用パターンを処理できます。ARCは、多くの一般的な使用パターンで非常によく機能しますが、いくつかの(有効な!)使用パターンでは、フォールバックして終了します。


「一方で、ARCでは一部のタイプのデータ構造が不可能な」ヒントがないと、自動クリーンアップは不可能だと思いました。明らかに、データ構造はそうです。
Steven Fisher、

もちろん、ARCではObjCオブジェクトの自動クリーンアップのみを使用できるため、「自動クリーンアップなし」==「クリーンアップなし」です。時間があれば、言い換えて答えます。
ストライプ

@Stripes:ARCでの手動クリーンアップに相当するのは、手動によるサイクルの中断ですfoo = nil
ダグラス

「[ARC]はパフォーマンスが高くなる傾向があります... ARCはパフォーマンスを優先します」。参照カウントがガベージコレクションのトレースよりもはるかに遅いことがよく知られている場合、私はそれを読んで驚いています。flyingfrogblog.blogspot.co.uk/2011/01/…–
Jon Harrop、

2
理論的には、GCの方が高速です(各参照カウント操作はマルチプロセッサキャッシュコヒーレントである必要があり、それらは多数あります)。実際には、ObjCで使用できる唯一のGCシステムははるかに低速です。GCシステムがスレッドをランダムにユーザーが認識できる時間だけ一時停止することも非常に一般的です(リアルタイムのGCシステムはいくつかありますが、一般的ではなく、「興味深い」制約があると思います)
Stripes

4

マジック

しかし、より具体的には、ARCは、コードで行うのとまったく同じことを実行します(特定の小さな違いがあります)。ARCはコンパイル時テクノロジーであり、ランタイムでありパフォーマンスに悪影響を与えるGCとは異なります。ARCはオブジェクトへの参照を追跡し、通常のルールに従って保持/解放/自動解放メソッドを合成します。このため、ARCは、純粋に慣例のために自動解放プールに投入するのではなく、不要になったものをすぐに解放することもできます。

その他のいくつかの改善には、弱参照のゼロ化、ヒープへのブロックの自動コピー、ボード全体の高速化(自動解放プールの場合は6倍!)が含まれます。

これがどのように機能するかについてのより詳細な議論は、ARCのLLVM Docsにあります。


2
-1「ランタイムでありパフォーマンスに悪影響を与えるGCとは異なり、ARCはコンパイル時のテクノロジです。」参照カウントは実行時に増加するため、非常に非効率的です。そのため、JVMや.NETなどのGCのトレースが非常に高速になります。
Jon Harrop、2014年

1
@ジョン:これの証拠はありますか?私の読書から、新しいRCアルゴリズムは通常、M&S GCと同じかそれ以上にパフォーマンスが良いようです。
xryl669 2014

1
@ xryl669:GCハンドブック(gchandbook.org)に詳しい説明があります。トレースは!= M&Sです。
Jon Harrop、2014年

3

ガベージコレクションとは大きく異なります。別の行でオブジェクトをリークしている可能性があることを通知する警告を見ましたか?これらのステートメントは、オブジェクトを割り当てた行を教えてくれます。これはさらに一歩進んだものであり、ほとんどのプログラマよりも適切な場所にretain/ releaseステートメントを挿入できるようになりました。ほぼ100%の時間です。ときどき、保持するオブジェクトの奇妙なインスタンスがあり、それを支援する必要があります。


0

Apple開発者のドキュメントで非常によく説明されています。「ARCの仕組み」を読む

必要なときにインスタンスが消えないようにするために、ARCは、各クラスインスタンスを現在参照しているプロパティ、定数、変数の数を追跡します。インスタンスへのアクティブな参照が少なくとも1つ存在する限り、ARCはインスタンスの割り当てを解除しません。

必要なときにインスタンスが消えないようにするために、ARCは、各クラスインスタンスを現在参照しているプロパティ、定数、変数の数を追跡します。インスタンスへのアクティブな参照が少なくとも1つ存在する限り、ARCはインスタンスの割り当てを解除しません。

違いを知ること。ガベージコレクションとARCの間:これを読む


0

ARCは、オブジェクトの自動メモリ管理を提供するコンパイラ機能です。

retain, release、およびをいつ使用するかを覚える必要はなくautorelease、ARCはオブジェクトの有効期間の要件を評価し、コンパイル時に適切なメモリ管理呼び出しを自動的に挿入します。コンパイラーは、適切なdeallocメソッドも生成します。

コンパイラーretain/releaseはコンパイル時に必要な呼び出しを挿入しますが、これらの呼び出しは他のコードと同様に実行時に実行されます。

次の図は、ARCがどのように機能するかを理解するのに役立ちます。

ここに画像の説明を入力してください

iOS開発の初心者で、Objective Cの実務経験がない方。メモリ管理の詳細については、Appleのドキュメント 『Advanced Memory Management Programming Guide』を参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.