1

説明が長くて申し訳ありませんが、質問はそれほど簡単ではありません...

私のプロジェクトはGCなしで書かれました。最近、見つけられないメモリ リークが見つかりました。結果なしで新しいXcode Analyzerを使用しました。コードを 1 行ずつ読み、すべての alloc/release/copy/autorelease/mutableCopy/retain と pools を確認しました... - まだ何もありません。

前文: Standard Instruments と Omni Leak Checker が何らかの理由で機能しません (Omin Tool がアプリを拒否し、Instruments.app (Leaks) がメモリと CPU を大量に消費するため、使用する機会がありません)。

だから私は自分のコードを書いて使って "all" alloc/allocWithZone:/dealloc メッセージの統計をフックして追跡し、いくつかの単純な独自のリークチェックライブラリを書きたいと思っています (主な目標は、オブジェクトのクラス名にリークの可能性をマークすることだけです)。

私が使用する主なフッキング手法:

  Method originalAllocWithZone = class_getClassMethod([NSObject class],@selector(allocWithZone:));
  if (originalAllocWithZone)
  {
   imp_azo = (t_impAZOriginal)method_getImplementation(originalAllocWithZone);
   if (imp_azo)
   {
    Method hookedAllocWithZone = class_getClassMethod([NSObject class],@selector(hookedAllocWithZone:));
    if (hookedAllocWithZone)
    {
     method_setImplementation(originalAllocWithZone,method_getImplementation(hookedAllocWithZone));
     fprintf(stderr,"Leaks Hook: allocWithZone: ; Installed\n");
    }
   }
  }
  • このようなコードで alloc メソッドをフックし、NSObject カテゴリ メソッドとして dealloc を割り当てます。

以前のメソッドの実装のために IMP を保存し、すべての alloc/allocWithZone: 呼び出しをインクリメント (+1) stat-array NSInteger 値として登録および計算し、dealloc 呼び出しをデクリメント (-1) として呼び出します。

エンドポイントとして、以前の実装を呼び出して値を返します。

コンセプトとしては、すべて問題なく動作します。

必要に応じて、クラスがクラス クラスター (NSString、NSPathStore2、NSDate、__NSCFDate など) の一部であることを検出することもできます... 正規化関数を使用します (ただし、以下で説明する問題については問題ありません)。

ただし、この手法にはいくつかの問題があります。

  • すべてのクラスをキャッチできるわけではありません。たとえば、[NSDate date] は alloc/allocWithZone でキャッチされません: まったく、しかし、GDB で alloc 呼び出しを確認できます
  • 自動シングルトン検出手法 (retainCount readind に基づく) を使用して、一部のオブジェクトを最終統計から自動的に除外しようとしているため、完全な Cocoa アプリケーション (実際には、単純な Objective-C コマンド ラインでさえも) を開始すると、NSLocale の作成が初期化前の段階でフリーズしますFoundation フレームワークが含まれているユーティリティには、main()) の前にいくつかの追加の初期化があります - GDB によって allocWithZone: が次々に呼び出されます....

ここにアップロードされた完全なコンセプト プロジェクト ドラフト ソース: http://unclemif.com/external/DILeak.zip (3.5 Kb)

Terminal.appからmakeを実行してコンパイルし、 . /conceptを実行して動作を確認します。


最初の質問: alloc & allocWithZone: メソッドをフックしても、すべてのオブジェクト割り当てをキャッチできないのはなぜですか?

2 番目の質問: allocWithZone をフックする理由: 一部のクラスの CFGetRetainCount (または [inst preserveCount]) でフリーズする...

4

3 に答える 3

6

車輪の再発明、バットマン!

あなたはこの道を必要以上に難しくしています。独自のオブジェクト トラッキング ツールを開発する必要はまったくありません (ただし、これは興味深い頭の体操です)。

GC を使用しているため、割り当てを追跡し、リークを特定するためのツールはすべて非常に成熟しています。

GC では、リークは 2 つの形式のいずれかになります。かなり前に破棄されたはずのオブジェクトへの強い参照が存在する、オブジェクトがCFRetainバランシングなしで 'dされましたCFRelease

コレクターは、特定のオブジェクトが歓迎されない理由を理解することに非常に長けています。

したがって、あまりにも長い間固執しているオブジェクトのセットを見つける必要があります。どんなオブジェクトでも構いません。上記のオブジェクトのアドレスを取得したら、Instruments の Object Graph インストゥルメントを使用して、オブジェクトが固執している理由を突き止めることができます。まだそれを参照しているもの、または保持されている場所を把握してください。

または、gdb からinfo gc-roots 0xaddr、オブジェクトをルートしているさまざまなものをすべて見つけるために使用します。malloc 履歴を有効にすると (malloc のマニュアル ページを参照)、参照を保持しているオブジェクトの割り当て履歴を取得できます。


ああ、GC なしで、ね...

まだ大量のツールが残っており、車輪を再発明する必要はありません。

コマンド ライン ツールを使用すると、多くのleaks場合、良い手がかりが得られます。mallocStackLoggingNoCompact をオンにして、malloc_history (別のコマンド ライン ツール) を使用できるようにします。

または、ObjectAlloc インストゥルメントを使用します。

いずれにせよ、リークされているオブジェクトを 1 つか 2 つ特定する必要があります。これで、何がぶら下がっているかを把握できます。非GCでは、それは完全に、リリースによってバランスが取れていない保持がある理由を理解するケースです.

于 2009-12-28T03:17:14.333 に答える
4

Leaks インストゥルメントがなくても、Instruments は役に立ちます。

Leaks テンプレートから始めて、そこから Leaks インストゥルメントを削除します (メモリの使用量が多すぎるため)。ObjectAlloc だけで、すべてのオブジェクトの割り当てと割り当て解除、および (Leaks テンプレートでデフォルトでオンになっているオプションを使用して) すべての保持と解放も通知されます。

まだ存在するオブジェクトのみを表示するように ObjectAlloc インストルメントを設定できます。オブジェクトが存在しない (または特定のクラスのオブジェクトが存在しない) ところまでアプリケーションを移動しても、そのようなオブジェクトがまだ存在する場合は、リークが発生しています。その後、ドリルダウンしてリークの原因を見つけることができます。

このビデオが役立つかもしれません。

于 2009-12-28T04:09:13.380 に答える
-2

Xcodeテンプレートから開始します。自分が何をしているのかがわかるまで、ココアアプリ用に独自のmain()ルーチンを実行しようとしないでください。

于 2009-12-28T02:08:34.217 に答える