2012-06-23 5 views
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 создает объект DungeonDisplay путем взаимодействия с другим объектом, DungeonLevel (я не думаю, что это особенно важно, чтобы выяснить, почему 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 (в Кокосовом методе) Сохранять счетчик переходит на 4 (с 1). «letTheDungeon» не влияет на количество удержаний (как и ожидалось).

+0

Можете ли вы предоставить небольшой контекст? Каким типом объекта является этот вызов, и какой объект является «DungeonDisplay»? Правильно ли я полагаю, что 'addChild' - это метод, который вы написали (и в этом случае вы можете поделиться этим кодом с нами тоже)? Когда я видел, что подсчеты прыгают так, это было результатом моего добавления в NSMutableArray/NSMutableDictionary и пренебрежения удалением из этой структуры. Но нам этого недостаточно, чтобы диагностировать его. Я знаю, что это больно, но можете ли вы дать нам больше контекста и больше связанного кода? – Rob

+0

Стационарный анализатор дает вам чистый счет здоровья? Shift-command-B - это все, что требуется для анализа вашего кода. – Rob

ответ

1

Спасибо за все ваши ответы. Проблема решена, и у меня снова есть незначительная утечка. Проблема была в CCTouchDispatcher в дочернем классе DungeonDisplay. Я изменил код для обработки касаний к классу подземелья и сделал некоторые другие незначительные корректировки, и все деаллок вызывают.

В любом случае, его твердый камень снова. Я переехал более ста раз туда и обратно, и их не было изменений в выделенной памяти. Фактически, я сейчас путешествую менее чем на 70 МБ, меньше, чем раньше.

Еще раз спасибо за ваши слова поддержки и поддержки.

7

Вопрос: «Мне трудно найти утечку памяти ... У кого-нибудь есть полный список конкретных вещей, которые увеличивают и уменьшают количество удержаний?»

Wow, тонны вещей. Просто сосредоточив внимание на том, что увеличивает количество накоплений, оно включает в себя: добавление subviews; толкающие/отображающие контроллеры; добавление в словари и массивы; любой метод, имя которого начинается с alloc, new, copy, или mutableCopy; любые retain invocations; создание объектов в коде, отличном от ARC, в viewDidLoad и пренебрежение их очисткой в ​​dealloc; выделение другого нового объекта в одном из ваших указателей в коде, отличном от ARC, который уже указывает на элемент, который еще не был выпущен; любая базовая функция основывается на create или copy на имя; и т. д. И это, вероятно, только царапины на поверхности. Список того, что уменьшает количество задержек, столь же длинный.

Без обид, это вряд ли будет продуктивным путем для отслеживания утечки. (Это как сказать, кто был расстрелян в Манхэттене, так что давайте получить список всех на Восточном побережье с ружьем.) Я хотел бы предложить вам проводить больше CSI подхода:

  1. Выполнить свой код через Xcode static analyzer. Пока вы не устраните все эти проблемы, нет смысла смотреть дальше. Вы должны получить ноль предупреждения из вашего статического анализа.

  2. Используйте инструменты профилировщика find the leak. После того, как вы узнаете, как использовать этот инструмент, он может часто показывать вам, какой именно объект и строка кода вызывает утечку, при котором разрешение точки намного проще.

  3. Обязательно прочитайте и поймите Advanced Memory Management. Если вы делаете что-либо с базовым основанием, проверьте также Memory Management Programming Guide for Core Foundation.

  4. Если вы не используете ARC, начните вводить отладочные сообщения, которые исследуют retainCount ваших различных объектов.

Если вы нашли кусок кода, который протечки, если вы не можете понять это, а затем разместить вредоносный код, здесь на StackOverflow (не забудьте сообщить нам, если это ARC или нет), и мы можем помочь вы диагностируете его дальше.

Я действительно не хочу быть забавным, но этот вопрос, поскольку он стоит, слишком широк для нас, чтобы помочь вам (и даже если кто-то теоретически может дать вам исчерпывающий ответ, я не могу себе представить, что это быть полезным для вас).Надеюсь, некоторые из приведенных выше советов будут указывать вам в правильном направлении.

Я серьезно понимаю ваше разочарование. Этот первый проект, в котором вы решите, что серьезно настроитесь на выявление утечек, - это болезненное упражнение. Вам нужно освоить нетривиальный мир управления памятью Objective-C и изучить некоторые довольно сложные инструменты (особенно профилировщик). Но как только вы пройдете упражнение один раз в большом проекте и освоите инструменты, у вас будет этот момент «ах-ха», а отслеживание утечек памяти станет простым (или, по крайней мере, методичным) процессом.

+3

CSI: Xcode. Где закончится отмирание? – jrturton

+2

Спасибо. Я редактировал сообщение. – user1437403

+2

Я проверил статический анализатор, и проблем не было (кроме как с библиотеками кокосов). Инструмент утечки не обнаружил значительных утечек, но это противоречило инструменту распределения, который показал, что память протекает (приводя к моим авариям). Я определил, какие deallocs не вызываются (с NSLogs), но не могу понять, почему счетчик удержания не падает правильно, поэтому его можно вызвать. – user1437403

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

Спасибо. Фактически, что я делаю, при другой функции в том же классе, когда вы готовы уйти, я [self removeChild: theDisplay], а затем [theDisplay release]; Я думаю, что это правильно, поскольку и alloc, и addchild увеличивают количество удержаний. – user1437403

+0

@ user1437403 Хотя я подозреваю, что это не связано с вашим оригинальным вопросом, я согласен с Морином в том, что хорошей практикой является освобождение (т. Е. Просто уменьшение количества удержания) прямо перед 'addChild' (либо явно, либо через авторекламу). Нет причин откладывать этот выпуск, и во многих случаях (хотя и не этот) он может спасти вам головные боли. Но я вижу из вашего другого ответа, что вы решили свою проблему. Замечательно! – Rob

+0

Спасибо. Я это сделаю. – user1437403

0

Хорошо, это может быть не «научно» правильно, но иногда вам нужно делать то, что вам нужно делать. Используйте инструмент «Инструменты зомби» следующим образом. В каком-то месте вашего кода, где вы ЗНАЕТЕ, что вы уже просочились в объект, выпустите [theLeakedObject_ release] столько раз, сколько нужно, чтобы зомбировать его. Затем в инструментах вы сможете получить следы удержания, класс которого увеличивает его, и который уменьшает его, в порядке, в котором это происходит, пока, очевидно, вы не станете зомбировать. Вы должны уметь «фиксировать» фиксатор, которого не должно быть там, и взять его оттуда.

пс. как личная практика, я следую примеру Мориона и придерживаюсь шаблона распределения авторезистов при создании объектов, которые выводятся из CCNode. Сохраняет вещи аккуратно и аккуратно, а очистка: ДА, салфетки процесса после меня очень хорошо :). И для любого другого бизнес-класса я специально сохраняю/освобождаю, чтобы оставить столько места в авторекладе для кокосов.

Смежные вопросы