Objective-Cの自動参照カウントはどのようなリークを防止または最小化しませんか?


235

MacおよびiOSプラットフォームでは、メモリリークは多くの場合、リリースされていないポインタが原因で発生します。従来、割り当て、コピー、保持をチェックして、それぞれに対応するリリースメッセージがあることを確認することが常に最も重要でした。

Xcode 4.2に付属しているツールチェーンでは、最新バージョンのLLVMコンパイラで自動参照カウント(ARC)が導入されています。これにより、コンパイラにデータをメモリ管理させることで、この問題を完全に回避できます。それはかなりクールであり、多くの不必要で平凡な開発時間を削減し、適切な保持/解放のバランスで簡単に修正できる多くの不注意なメモリリークを防ぎます。MacとiOSアプリでARCを有効にするときは、自動解放プールでさえ別の方法で管理する必要があります(独自NSAutoreleasePoolのをもう割り当てる必要がないため)。

しかし、他のどのメモリリークで、私がまだ注意しなければならないことを妨げていませんか?

おまけとして、Mac OS XとiOSのARCとMac OS Xのガベージコレクションの違いは何ですか?

回答:


262

注意すべき主なメモリ関連の問題は、保持サイクルです。これは、あるオブジェクトが別のオブジェクトへの強いポインタを持っているが、ターゲットオブジェクトが元のオブジェクトへの強いポインタを持っている場合に発生します。これらのオブジェクトへの他のすべての参照が削除された場合でも、それらは引き続き互いに保持され、解放されません。これは、チェーンの最後のオブジェクトが以前のオブジェクトを参照している可能性があるオブジェクトのチェーンによって間接的に発生することもあります。

このため、__unsafe_unretainedおよびの__weak所有者修飾子が存在します。前者はポイントするオブジェクトを保持しませんが、そのオブジェクトが消えて不良メモリをポイントする可能性を残しますが、後者はオブジェクトを保持せず、ターゲットの割り当てが解除されると自動的にnilに設定します。2つのうち、__weakそれをサポートするプラットフォームでは一般的に推奨されます。

これらの修飾子はデリゲートのようなものに使用しますが、オブジェクトがデリゲートを保持して、サイクルにつながる可能性はありません。

メモリに関連するもう1つの重要な問題は、Core Foundationオブジェクトの処理と、次を使用して割り当てられたメモリです。 malloc()ような型にchar*です。ARCはこれらのタイプを管理せず、Objective-Cオブジェクトのみを管理するので、自分で処理する必要があります。Core Foundationの型は、一致するObjective-Cオブジェクトにブリッジしたり、その逆を行ったりする必要がある場合があるため、特に注意が必要です。これは、CFタイプとObjective-Cの間をブリッジするときに、ARCから制御を前後に転送する必要があることを意味します。このブリッジングに関連するいくつかのキーワードが追加されました。また、Mike Ashは、彼の長いARCの記事さまざまなブリッジングのケースについて素晴らしい説明をしています。

これに加えて、他のいくつかのそれほど頻繁ではありませんが、まだ潜在的に問題のあるケースがあります。 公開された仕様は詳細に説明されています。

新しい動作の多くは、オブジェクトへの強いポインタがある限りオブジェクトを保持することに基づいており、Macのガベージコレクションとよく似ています。ただし、技術的な基盤は大きく異なります。指されなくなったオブジェクトをクリーンアップするために定期的に実行されるガベージコレクタープロセスを持つのではなく、このスタイルのメモリ管理は、Objective-Cですべて従う必要がある厳格な保持/解放ルールに依存しています。

ARCは、何年にもわたって行わなければならなかった反復的なメモリ管理タスクを単純に取り、それらをコンパイラーにオフロードするので、再び心配する必要はありません。これにより、ガベージコレクションされたプラットフォームで発生する停止の問題やノコギリ状のメモリプロファイルがなくなります。私はガベージコレクションされたMacアプリケーションでこれらの両方を経験し、ARCでの動作を知りたいと思っています。

ガベージコレクションとARCの詳細については、Objective-CメーリングリストでChris Lattnerによるこの非常に興味深い応答を参照してください。ここでは、Objective-C 2.0ガベージコレクションに対するARCの多くの利点を挙げています。彼が説明するGCの問題のいくつかに遭遇しました。


2
詳細な回答ありがとうございます。_unsafe_unretainedでデリゲートを定義してアプリケーションをクラッシュさせたのと同じ問題がありましたが、後で強力に変更して修正しましたが、メモリリークが発生しています。なので弱めに変更してチャームのように動作します。
チャトゥラム2013年

@ichathuraすごい!あなたは私をARCの泥沼から救った。CMPopTipViewを使用すると、同じクラッシュが発生しました。
Nianliang 2013年

@BradLarson:「ガベージコレクションされたプラットフォームで発生する停止の問題や鋸歯状のメモリプロファイルはありません」。スコープベースの再利用による停止と鋸歯状のメモリプロファイルの悪化、および参照カウントによるパフォーマンスの低下が予想されるので、実際の比較を見てみたいと思います。
Jon Harrop

ブラッド、クリス・ラトナーからのリンクは死んでいる。私は100%ではありませんが、この別のリンクを見つけました。:どの私はあなたへのリンクに欲しかったものだと思うlists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/...
ハニー

1
@ハニー-指摘してくれてありがとう。リンクするものは少し異なりますが、元のメッセージのアーカイブバージョンでデッドリンクを置き換えました。どこかで利用できるはずのメーリングリストアーカイブにありますが、新しい場所が見つかるかどうかを確認します。
ブラッド・ラーソン

14

ARCは、ObjC以外のメモリについてはサポートしません。たとえば、malloc()何か必要な場合でも、それが必要free()です。

performSelector:コンパイラーがセレクターが何であるかを理解できない場合、ARCはだまされる可能性があります(コンパイラーは警告を生成します)。

ARCはObjC命名規則に従ってコードも生成するため、ARCとMRCコードを混在させると、MRCコードがコンパイラーが名前で約束していることを実行しない場合、驚くべき結果が得られます。


7

次の4つの問題が原因で、アプリケーションでメモリリークが発生しました。

  1. View Controllerを閉じるときにNSTimersを無効にしない
  2. ビューコントローラを閉じるときに、NSNotificationCenterのオブザーバを削除するのを忘れる。
  3. ブロック内での自己への強い参照の維持。
  4. ビューコントローラーのプロパティでデリゲートへの強い参照を使用する

幸い、私は次のブログ投稿に出会い、それらを修正することができました。http//www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-likely-culprits/


0

ARCはCoreFoundationタイプも管理しません。それらを「ブリッジ」することができます(を使用CFBridgingRelease())。ただし、Objective-C / Cocoaオブジェクトとして使用する場合のみ。CFBridgingReleaseはCoreFoundation保持カウントを1だけ減らし、それをObjective-CのARCに移動することに注意してください。


0

Xcode 9は、そのような問題を見つけるための優れたツールを提供します。それは: " デバッグメモリグラフ」。これを使用すると、クラスタイプごとにリークしたオブジェクトを見つけることができ、そこから解放することで、そのオブジェクトへの強い参照を保持しているユーザーを明確に確認して、問題を解決できます。また、メモリサイクルを検出します。

使い方の詳細はこちら

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