2

メモリリークを見つけるのに問題があります。私はcocos2dを使用しています。これは、2つのクラスのデータ領域です。

@interface Dungeon : CCLayerColor {
    DungeonLevel *aDungeonLevel;
    Player *thePlayer;

    // list of all monster file names
    NSMutableArray *monsterNames;

    // array of how many monsters there are of each monster level
    NSMutableArray *monsterLevels;

    MessageView *theMessageView;

    DungeonDisplay *theDisplay;

    bool processing;

    int currentDungeonLevel;    
}

@interface DungeonDisplay : CCLayerColor {
    NSMutableArray *displayGrid;
    NSMutableArray *displayGrid2;
    NSMutableArray *displayGrid3;
    NSMutableArray *displayGrid4;
    NSMutableArray *dungeonMatrix;
    NSMutableArray *monsterSprites;
    Dungeon *theDungeon;  
    int xdelt;
    int ydelt;
    CGPoint lowerLeft;
    Player *thePlayer;
    CCSprite *playerSprite;
    CCSprite *mSprite1;

    ButtonsLayer *buttonArea;

    double previousTime;
    double currentTime;
    double touchTimePrev;
    bool touchFlag;
    bool processing;
    bool processing2;
    bool animating;
    bool flipSprite;
    bool doIdleAnimation;
    bool isAttacking;
    int firstIteration;
    CGPoint dungeonOriginalPosition;
    CGPoint playerOriginalPosition;
    CGPoint mSprite1Original;
    CGPoint buttonOriginal;
    CCTimer *myTimer;

    // List of Messages
    NSMutableArray *messages;    
    int messageIndex;

    // player transparency level
    int transparency;

    // indicates that walls need to become transparent
    bool needTransparency;

    int pXInc;
    int pYInc;
    int tempx;
    int tempy;

    // debugging variables
    CCLabelTTF *debugLabel1;
    CCLabelTTF *debugLabel2;

    // the Map
    MiniMap *aMap;
}

さて、これでDungeonオブジェクトは別のオブジェクトDungeonLevelと対話することによってDungeonDisplayオブジェクトを作成します(DungeonDisplayが割り当て解除されない理由を理解することに特に関係があるとは思いません)。これは、「シングルトン」DungeonDisplayオブジェクトを作成するためのすべてのコードです。

-(void) displayDungeon
{
    if (!theDisplay) {
        theDisplay = [[DungeonDisplay alloc]init];
        [self addChild:theDisplay z:101];
        [theDisplay letTheDungeon:self];    
    }
    else {
        [thePlayer placePC:thePlayer.pCLocation];
        [theDisplay displayStructure];
    }
    theDisplay.visible = true;
    aDungeonLevel.visible = NO;
}

何らかの理由で、addChild(cocosメソッド)の後、保持カウントは(1から)4にジャンプします。「letTheDungeon」は(予想どおり)保持カウントに影響を与えません。

4

4 に答える 4

7

質問:「メモリリークを見つけるのに苦労しています。...保持数を増減する特定のものの包括的なリストを持っている人はいますか?」

回答:うわー、たくさんのこと。保持カウントを増やすものに焦点を当てるだけで、次のことが含まれます。サブビューの追加。コントローラーのプッシュ/提示; 辞書と配列に追加する。名前が、、、、または;allocで始まるメソッド。呼び出し; で非ARCコードでオブジェクトを作成し、でそれらをクリーンアップすることを怠ります。まだリリースされていないアイテムをすでに指している非ARCコードのポインターの1つに別の新しいオブジェクトを割り当てます。名前のある、または名前の中にあるコアファンデーション機能。など。そして、これはおそらく表面を傷つけるだけです。保持カウントを減らすもののリストも同じくらい長いです。newcopymutableCopyretainviewDidLoaddealloccreatecopy

不快感はありません。これがリークを追跡するための生産的なルートになる可能性は低いです。(マンハッタンで誰かが撃たれたと言っているようなものなので、銃を持って東海岸の全員のリストを取得しましょう。)CSIアプローチをもっと追求することをお勧めします。

  1. Xcode静的アナライザーを介してコードを実行します。これらの問題をすべて修正するまで、これ以上調べる意味はありません。静的分析から警告がゼロになるはずです。

  2. プロファイラーツールを使用して、リークを見つけます。そのツールの使用方法を学ぶと、多くの場合、リークの原因となっているオブジェクトとコード行を正確に示すことができ、その時点で解決がはるかに簡単になります。

  3. AdvancedMemoryManagementを完全に読んで理解していることを確認してください。Core Foundationで何かをしている場合は、CoreFoundationのメモリ管理プログラミングガイドも確認してください。

  4. retainCountARCを使用していない場合は、さまざまなオブジェクトを調べるデバッグメッセージの入力を開始してください。

リークしているコードを見つけた場合、それがわからない場合は、ここに問題のあるコードをStackOverflowに投稿してください(ARCかどうかを必ずお知らせください)。さらに診断をお手伝いします。

私は本当に卑劣なことを意味するわけではありませんが、この質問は、現状では、私たちがあなたを助けるには広すぎます(そして誰かが理論的にあなたにあなたの包括的な答えを与えることができたとしても、それがまったく役立つとは想像できませんあなたへ)。ただし、上記のヒントのいくつかが正しい方向を示してくれることを願っています。

私はあなたの欲求不満を真剣に受け止めます。リークの追跡に真剣に取り組むことを決定した最初のプロジェクトは、骨の折れる作業です。Objective-Cのメモリ管理の重要な世界をマスターし、かなり複雑なツール(特にプロファイラー)を学ぶ必要があります。しかし、大きなプロジェクトで一度演習を行い、ツールを習得すると、その「あはは」の瞬間があり、メモリリークの追跡は単純な(または少なくとも系統だった)プロセスになります。

于 2012-06-23T05:33:26.773 に答える
1

すべての回答をありがとう。問題は解決され、私は再びわずかな漏れがあります。問題は、子クラスDungeonDisplayのCCTouchDispatcherにありました。タッチを処理するためのコードをダンジョンクラスに変更し、その他の小さな調整を行ったところ、すべてのdeallocが呼び出されています。

とにかく、その岩は再びしっかりしています。私は100回以上前後に移動しましたが、割り当てられたメモリに変更はありませんでした。実際、私は現在70 MB未満でクルージングしており、以前よりも少なくなっています。

特に励ましとサポートの言葉をありがとう。

于 2012-06-23T16:02:11.687 に答える
1

リークを引き起こす可能性のある最初の原因は、作成されたDisplayインスタンスを解放しないことです。コードを次のように変更します

if (!theDisplay) 
{
    theDisplay = [[DungeonDisplay alloc]init];
    [self addChild:theDisplay z:101];
    [theDisplay release];  // add this line
    [theDisplay letTheDungeon:self];    
}

また

if (!theDisplay) 
{
    theDisplay = [[[DungeonDisplay alloc] init] autorelease];  // create autoreleased object
    [self addChild:theDisplay z:101];
    [theDisplay letTheDungeon:self];    
}

少なくとも1つのメモリの問題を解決します。

于 2012-06-23T08:36:10.070 に答える
0

わかりました、これは「科学的に」正しくないかもしれません、しかし時々あなたはあなたがしなければならなかったことをしなければなりません。次のようにInstrumentsZombiesツールを使用します。すでにオブジェクトをリークしていることがわかっているコードのどこかで、ゾンビを出すのに必要な回数だけ[theLeakedObject_release]を発行します。次に、インストゥルメント内で、保持カウントのトレースを取得できます。保持カウントは、明らかにゾンビアウトするまで、発生順に、どのクラスが増加し、どのクラスが減少します。そこにあるべきではないリテーナを「見つけて」、そこから取り出すことができるはずです。

ps。個人的な慣習として、CCNodeから派生するオブジェクトを作成するときは、Morionの提案する慣習に従い、自動解放割り当てパターンを使用します。物事をきちんと整頓し、cleanup:YESプロセスは私の後に非常によくワイプします:)。そして、他のビジネスクラスの場合、私は特に、ココスの自動解放プールにできるだけ多くのスペースを残すために保持/解放します。

于 2012-06-23T13:55:00.577 に答える