2

retainCount次の質問の単語が表示される前に、[OK ]を押してください。使用を停止したと述べた下部の[編集]にスキップしてください。

MRRを使用する私のCocoaアプリは、呼び出されるmain()前に、ロードしている多くのグローバルリソースを作成します。戻らないので、次のように、を使用してこれらのリソースのクリーンアップをフックしましNSApplicationMain()た。NSApplicationMain()atexit()

atexit(cleanup);

if (![CocoaUtil initCocoaUtil] ||
    ![PreferenceController initPreferenceController] ||
    ![ResourceManager initResourceManager])
{
    criticalAlertPanel(@"Failed to initialize application",
                       @"Failed to initialize application");
    return 4;
}

retval = NSApplicationMain(argc, (const char **)argv);

ただし、サブクラスのビューが'dcleanup()になる前に呼び出されるため(これを示すログメッセージがありません)、グローバルリソース内のオブジェクトの参照カウントが時々発生します。私は慎重すぎて、この方法を使用してグローバルリソースを解放することにより、メモリリークを回避しようとしています。NSDocumentdealloc> 1

+ (void)fullRelease:(id)obj
             format:(NSString *)format, ...
{
    if (obj == nil)
        return;

    NSUInteger retainCount = [obj retainCount];
    if (retainCount > 1)
    {
        va_list va;
        va_start(va, format);
        NSString *objDesc = [[NSString alloc] initWithFormat:format arguments:va];
        logwrn(@"%@ has a reference count of %lu", objDesc, retainCount);
        [objDesc release];
    }

    while (retainCount > 0)
    {
        [obj release];
        retainCount--;
    }
}

私のログには次のように表示されます。

12:15:04.954 INF -[AppController applicationDidFinishLaunching:] Application launched
12:15:06.702 INF -[AppController applicationShouldTerminate:] Application terminating
12:15:06.703 INF -[AppController applicationWillTerminate:] Application terminating
12:15:06.705 DBG cleanup Cleaning-up
12:15:06.705 INF +[ResourceManager finiResourceManager] Cleaning up
12:15:06.709 WRN +[CocoaUtil fullRelease:format:] _images[2] has a reference count of 2
12:15:06.709 WRN +[CocoaUtil fullRelease:format:] _images[3] has a reference count of 2
12:15:06.709 WRN +[CocoaUtil fullRelease:format:] _images[4] has a reference count of 2
12:15:06.710 WRN +[CocoaUtil fullRelease:format:] _images[5] has a reference count of 2
12:15:06.710 WRN +[CocoaUtil fullRelease:format:] _images[6] has a reference count of 2
12:15:06.710 WRN +[CocoaUtil fullRelease:format:] _images[7] has a reference count of 2
12:15:06.711 WRN +[CocoaUtil fullRelease:format:] _images[8] has a reference count of 2
12:15:06.711 WRN +[CocoaUtil fullRelease:format:] _images[9] has a reference count of 2
12:15:06.721 DBG +[PreferenceController finiPreferenceController] Cleaning up
12:15:06.721 DBG +[CocoaUtil finiCocoaUtil] Cleaning up

私の質問(ついに!)は:

NSDocumentすべてのインスタンスが破棄された後、グローバルリソースを確実にクリーンアップして、これらのフォールスネガティブの取得を停止する方法はありますか?

編集fullRelease呼び出しのフックを解除し、リソースに対して通常の処理を実行しましたがrelease、Instrumentsはメモリリークを検出しなかったため、問題はありませんが、呼び出されるNSDocument前にオブジェクトが解放されていないように見える理由に興味があります。atexit()

4

4 に答える 4

7

所有していないものをリリースしないでください。

すべての保持は他の誰かに属します。、、、または(NARC)releaseへの呼び出しのバランスをとるためにのみ、オブジェクトに送信します。この種の動作は、必然的に製品コードでクラッシュを引き起こします。newalloccopyretain

オブジェクトが単に処理されるのではなく、割り当てが解除されていることを確認したいようです。オブジェクトを所有している場合は、一度解放します。それに対する他の参照は、他のオブジェクトに属します。コードにメモリ リークがある可能性はありますが (このコード サンプルだけでは判断できません)、通常は Static Analyzer、Instruments、および少しの作業で発見できます

さらに重要なことは、プロセスが終了すると、オペレーティング システムがすべてのメモリを解放することです。これは C 標準の一部ではありませんが、単に OS X と iOS が動作する方法であり、Objective-C をサポートする他のプラットフォームで期待される動作です。したがって、ファイルをディスクなどに書き込む場合を除いて、プロセスが終了したときにクリーンアップするために特別なことをする必要はありません。実際、多くの Cocoa アプリケーションは、アプリケーション デリゲートが所有するものを解放することを気にしません-release。これは、何千ものオブジェクトを呼び出すよりも、オペレーティング システムにメモリをダンプさせる方が速いためです。

電話しないでください-retainCount

嘘です。簡潔でシンプル。これには Cocoa が使用する一時的な参照が含まれており、最も重要なことであり、それらに干渉しようとしないでください。-retainCount毒のシンボルです。

于 2012-08-25T12:06:33.903 に答える
3

突然の終了を無効にし、グローバルを使用せず、通常の参照カウント ルールのみを使用します。場合によっては、強い循環参照を解除するか、オブジェクトのインスタンス変数を手動でクリアする必要があります。最後に、メインが戻る前に一時停止/中断heapし、この段階で何が実際に生きているか (リーク) を確認するために実行する方が役立つ場合があります。

私は用心深く、このメソッドを使用してグローバル リソースを解放することで、メモリ リークを未然に防ごうとしています。

このようにパージするべきではありません-あなたはよく知っています:)

ただし、制御できるすべての参照/オブジェクト/割り当てを見つけて破棄することは、実際には非常に優れた方法であり、プログラムが適切に機能し、再利用可能であり、アプリの変更に伴う回帰を監視するための優れた指標となります。

于 2012-08-25T12:39:35.317 に答える
2

他のすべての人が言っているように、自分が所有しているものだけを解放してください。アプリがクラッシュすることはないかもしれませんが、運がよくなっているだけです。これを行うと、または2時間後などに、別のMacでクラッシュする可能性があります.

一部のオブジェクトが保持しているリソースが不足していて、それを実際に登録解除する必要がある場合 (たとえば、別のサーバーへのネットワーク セッションで、サインオフ メッセージを正しく送信しないと、サーバーが待機し、一部を保持します)。戻りの内部状態)、オブジェクトが解放されたときにそれを行うのではなく、それをオブジェクトに組み込む必要があります。

たとえば、アプリケーションが終了する前に Mac OS X が送信する通知、NSApplicationWillTerminate があります。オブジェクトを登録し、それを取得したら、サーバーにさようならを送信します (そして、既にそれを行っていることを思い出してください)。そうすれば、アプリケーションが終了しても、たとえばアプリケーション デリゲートがまだそのオブジェクトを保持している場合でも、サインオフが確実に行われます。

ただし、-dealloc で既にサインオフしているかどうかも確認する必要があります。ある日、複数のサーバーのサポートを追加し、1 つのサーバーをリリースするときに、アプリが終了しなくても、そのサーバーにさようならを送信してもらいたいとします。ただし、サインオフをまだ行っていない場合にのみ行ってください。

終了する前に書き留めておきたいデータがメモリにある場合も同様です (たとえば、設定へのアクセスが高速であることを確認するために NSUserDefaults が行うことですが、終了する前にディスクに書き込まれます)。

しかし、そのようなケースは本当にまれです。通常、NSDocument は必要に応じてディスクへの書き込みを要求します。通常、サーバーは接続が切断されたことに気づき、自動的にクリーンアップします。したがって、自分のものではないものをリリースするべきではありません。一部のユーザーの終了時にクラッシュが発生するだけです。これは非常に悪い印象を与え、データを保存する機会を得る前にアプリが実際に失敗する可能性があり、事態を悪化させる可能性があります。

于 2012-08-25T16:25:55.787 に答える