影响保留计数的因素

时间:2012-06-23 04:59:57

标签: objective-c ios xcode cocos2d-iphone

我很难找到内存泄漏。我正在使用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未被解除分配的原因特别相关)。这是创建“singleton”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 个答案:

答案 0 :(得分:7)

问题:“我很难找到内存泄漏。...有没有人能够详细列出增加和减少保留计数的具体事项?”

答案:哇,很多东西。只关注增加保留计数的内容,它包括:添加子视图;推/控制器;添加到词典和数组;名称以allocnewcopymutableCopy开头的任何方法;任何retain次调用;在viewDidLoad中的非ARC代码中创建对象,而忽略了在dealloc中清理它们;在非ARC代码中的一个指针中分配另一个新对象,该指针已指向尚未释放的项目;任何核心基础在名称中使用createcopy;这可能只是划伤了表面。降低保留计数的列表同样长。

没有冒犯,这不太可能成为追踪泄漏的有效途径。 (这就像说有人在曼哈顿开枪一样,所以让我们拿一把东海岸的每个人拿着枪的清单。)我建议你采用更多的CSI方法:

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

  2. 使用探查器工具find the leak。一旦您学会了如何使用该工具,它通常可以准确地向您显示哪个对象和代码行导致泄漏,此时分辨率更容易。

  3. 确保您完全阅读并理解Advanced Memory Management。如果您正在使用核心基础,请查看Memory Management Programming Guide for Core Foundation

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

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

    我真的不是故意嗤之以鼻,但这个问题,就目前来说,太宽泛了,我们无法帮助你(即使理论上有人能给你全面的答案,我也无法想象它会是对你有帮助)。希望上面提到的一些技巧会指出你正确的方向。

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

答案 1 :(得分:1)

第一个可能导致泄密的是你没有发布创建的theDisplay实例。将您的代码更改为

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];    
}

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

答案 2 :(得分:1)

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

无论如何,它的坚如磐石。我来回移动了一百次,分配的内存没有变化。事实上,我现在的巡航速度低于70 MB,比以前少了很多。

再次感谢,特别感谢您的鼓励和支持。

答案 3 :(得分:0)

好吧,这可能不是'科学'正确的,但有时你必须做你应该做的事情。使用Instruments Zombies工具如下。在代码中你知道已经泄漏了一个对象的某个地方,发出[theLeakedObject_ release]多次,就像僵尸一样。然后在乐器中,你将能够获得保留计数的痕迹,该类增加它,并按顺序减少它,直到明显你僵尸出来。您应该能够“找到”不应该存在的保留器,并从那里取出它。

PS。作为个人实践的问题,我在创建源自CCNode的对象时遵循Morion的建议练习并坚持使用自动释放分配模式。保持干净整洁,清理:YES流程擦拭我很好:)。对于任何其他商务舱,我特别保留/释放在科罗拉的自动释放池中留下尽可能多的空间。