2

我很难找到内存泄漏。我正在使用 cocos2d。这是两个类的数据区:

@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 方法)之后,保留计数跳到 4(从 1)。“letTheDungeon”对保留计数没有影响(如预期的那样)。

4

4 回答 4

7

问题: “我很难找到内存泄漏。......有没有人有一个关于增加和减少保留计数的具体事情的完整列表?”

答案:哇,很多东西。只关注增加保留计数的因素,它包括:添加子视图;推送/展示控制器;添加到字典和数组;任何名称以allocnewcopy或开头的方法mutableCopy;任何retain调用;在非 ARC 代码中创建对象viewDidLoad并忽略在 中清理它们dealloc;在非 ARC 代码中的一个指针中分配另一个新对象,该指针已经指向尚未发布的项目;create任何具有或名称的核心基金会职能copy;等等,这可能只是表面上的问题。减少保留计数的列表也一样长。

无意冒犯,这不太可能是追踪泄漏的有效途径。(这就像说有人在曼哈顿被枪杀,所以让我们列出东海岸持枪的每个人的名单。)我建议你更多地采用 CSI 方法:

  1. 通过Xcode 静态分析器运行您的代码。在您解决所有这些问题之前,没有必要进一步研究。您应该从静态分析中获得警告。

  2. 使用分析器工具查找泄漏。一旦您学会了如何使用该工具,它通常可以准确地向您显示导致泄漏的对象和代码行,此时解决方案要容易得多。

  3. 确保您完全阅读并理解高级内存管理。如果您正在使用核心基础做任何事情,还请查看核心基础的内存管理编程指南

  4. 如果您不使用 ARC,请开始输入调试消息以检查retainCount您的各种对象。

如果您发现有一段代码泄漏,如果您无法弄清楚,那么在 StackOverflow 上发布有问题的代码(确保告诉我们它是否是 ARC),我们可以帮助您进一步诊断。

我真的不是要刻薄,但是这个问题就目前而言,太宽泛了,我们无法帮助您(即使理论上有人可以为您提供全面的答案,我也无法想象它会有所帮助给你)。不过,希望上述一些技巧能为您指明正确的方向。

我真的很理解你的挫败感。第一个你决定认真追踪泄漏的项目是一个痛苦的练习。你必须掌握 Objective-C 内存管理的重要世界,并学习一些相当复杂的工具(尤其是分析器)。但是一旦你在一个大项目中完成了一次练习,并掌握了工具,你就会有那种“啊哈”的感觉,追踪内存泄漏将成为一个简单(或至少有条理)的过程。

于 2012-06-23T05:33:26.773 回答
1

感谢您的所有回答。问题解决了,我再次有微不足道的泄漏。问题在于子类 DungeonDisplay 中的 CCTouchDispatcher。我将处理触摸的代码更改为地牢类,并进行了一些其他小的调整,每个人都被调用了 dealloc。

无论如何,它再次坚如磐石。我来回移动了一百多次,分配的内存没有变化。事实上,我现在的速度低于 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];    
}

它将解决至少一个内存问题。

于 2012-06-23T08:36:10.070 回答
0

好吧,这可能不是“科学”正确的,但有时你必须做你必须做的事情。按如下方式使用 Instruments Zombies 工具。在你知道你已经泄露了一个对象的代码中的某个地方,发出 [theLeakedObject_release] 的次数与它僵尸出的次数一样多。然后在仪器中,您将能够获得保留计数的踪迹,哪个类增加它,哪个类减少它,按照它发生的顺序,直到很明显你僵死了。您应该能够“发现”一个不应该存在的保持器,然后从那里拿走它。

附言。作为个人实践,在创建从 CCNode 派生的对象时,我遵循 Morion 的建议实践并坚持使用自动释放分配模式。保持东西整洁,清理:是的过程很好地在我之后擦拭:)。对于任何其他商务舱,我特别保留/释放,以便在自动释放池中为 cocos 留出尽可能多的空间。

于 2012-06-23T13:55:00.577 回答