„EXC_BAD_ACCESS: Не може да се възстанови предварително избран кадър“ - променливите на стека не се почистват

Във връзка с въпроса тук.

Решенията, предоставени в тази тема, включват:

  1. Ако сте умни къде и колко променливи декларирате, това ще отиде в стека.
  2. Деактивирайте Guard Malloc, ако е необходимо.

Освен това като цяло: 3. Уверете се, че освобождавате променлива, за която всъщност сте заделили памет!!

Нямам нито един от горните проблеми. Има много малко разпределени в стека променливи, които използвам във функциите, да речем 2-3 във всяка. Но тъй като функциите се извикват в цикъл няколко пъти, изглежда, че задейства изключение.

И тук е кикърът, това не се случва само за статично разпределени променливи, но и за неща в купчината! Получавам грешки в страницата на автоматично освободени декларации на променливи NSNumber, които използвам няколко вътре в цикъла, както и речник, който разумно разпределям и освобождавам в рамките на обхвата на функцията, всеки път, когато се извиква.

И така, защо се случва това и защо, по дяволите, променливите на купчината се засягат? Изобщо не разбирам, моля, хвърлете малко светлина върху това. :)

Аз съм на IOS5 с XCode 4.2, iPhone/iPad симулатор.

Благодаря!

Поздрави, Dev

Редактиране: Примерен код
- (void)doSomething {
NSInteger fun = 3;
NSInteger time = 4;
NSInteger overload = fun*time;
NSString *string = [NSString stringWithFormat:@"%d",overload];
NSObject *myCustomObject = [[NSObject alloc] init];
[myCustomDictionary setObject:myCustomObject forKey:string];
[myCustomObject release];
//myCustomDictionary is an iVar, alloced in the class's init method, and released in dealloc and not touched anywhere in between
}
//doSomething gets called several times through the course of execution as the state of the view changes, the user interacts with it etc, often 2-3 times during one state change.

Кодът нарочно е неясен, но в същото време е ТОЧНО толкова прост, колкото в примера. Както и останалата част от кода в целия проект. Няколко функции, всяка от които върши малко работа, толкова добре самостоятелни по отношение на паметта, колкото тази.

Преди се сблъсках с проблеми с EXC_BAD_ACCESS и в този момент се позовах на този въпрос. В моя случай обаче не създавах множество променливи в стека в рамките на цикъл, те се създаваха многократно от функция, която се извиква няколко пъти в хода на изпълнението. В идеалния случай променливите трябва току-що да са унищожени в края на функционалния обхват. Не знам защо това не се случи.

Както и да е, за да разреша това и да предотвратя случването на множество разпределения, накрая декларирах моите разпределени в стека променливи като всички static. Това е лоша практика, но точно това трябваше да направя, за да проработи. И работеше, докато не се сблъсках ОТНОВО с проблема с функцията "doSomething".

Така че трудността в "doSomething" беше, че не създавах само разпределени в стека променливи, но и куп неща. Така че първо започнах да получавам EXC_BAD_ACCESS на променливите NSInteger, след което се опитах да го поправя отново, като ги декларирах като статични. Проработи, но сега EXC_BAD_ACCESS започна да се появява на автоматично освободената променлива и накрая на персонализираната променлива - това беше моментът, в който се затрудних. Спазвам всички правила за управление на паметта и имам променливи на стека и купчината, които се блъскат навсякъде по мен. Ако беше само купчина неща или стек неща вътре в цикъл, можех да разбера, че има грешка НЯКЪДЕ. Но тук не е нито едното, нито другото, това са съвършено невинни променливи, които се разпределят в стека вътре в ЕДНА функция, която НЕ се извиква в цикъл, и обикновени автоматично освобождавани променливи, които никога не се запазват или освобождават, хвърлени към тях от друго място в кода. Това, което прави всичко още по-лошо, е, че точките на отказ са произволни - не само в тази функция, но практически всяка, която се извиква няколко пъти в хода на изпълнение на проекта.

Edit2: Оказва се, че в този случай вината е моя. Вижте моя отговор за подробности. Съжалявам, че губя времето на хората. :\


person Dev Kanchen    schedule 15.02.2012    source източник


Отговори (3)


Не можем наистина да ви помогнем, без да видим цялото проследяване на стека. EXC_BAD_ACCESS не означава нищо, за да отстраним проблема, трябва да знаем какво е изключението.

Въз основа на моя опит, когато не получите стек tarce, това означава, че освобождавате двойно. Zombies е начинът да намерите двойното си освобождаване.

Отидете на: Product -> Profile и след това изберете „Zombies“ от списъка. Стартирайте приложението и изпълнете всяка задача, която причинява срива, ако проблемът е двойно освобождаване, ще се появи изскачащ прозорец. Изберете стрелката в изскачащия прозорец и тя ви казва точно кой обект се освобождава двойно и ви показва цикъла на задържане.

person aryaxt    schedule 16.02.2012
comment
Моля, вижте моя отговор. Не мога да го приема в момента, тъй като изглежда, че мога да приема собствения си отговор само след 2 дни от задаването на въпроса или нещо подобно. - person Dev Kanchen; 16.02.2012
comment
И както споменах, Zombies биха били приложими за обекти, декларирани в купчината. Бях изправен пред същия проблем и със STACK променливите, така че не беше проблем със запазване/освобождаване, доколкото беше, че приложението просто изчерпваше паметта след x итерации на безкраен цикъл, както беше изяснено в моя отговор. - person Dev Kanchen; 16.02.2012

Без какъвто и да е код, публикуван във вашия въпрос, и виждайки, че използвате iOS 5 и Xcode 4.2, най-добрият ми съвет за вас е, в Xcode, отидете на Edit>Refactor>Convert to Objective-C ARC и помахайте сбогом на всичките си главоболия с управлението на паметта.

ARC извършва цялото управление на паметта вместо вас. Не е необходимо да запазвате, освобождавате или записвате методи за dealloc. В повечето случаи не е нужно да се притеснявате за управлението на паметта. Ще оставите зад гърба си мистериозни EXC_BAD_ACCESS сривове. Начинът, по който работи е супер ефективен. Компилаторът поставя запазванията и освобождаванията вместо вас и след това оптимизира. Никога дори не трябва да виждате кода.

person jackslash    schedule 15.02.2012
comment
Проблемите са свързани както със статично разпределени обекти, така и с чисто автоматично освободени обекти, а не с персонализирани, така да се каже, така че се съмнявам, че ARC ще помогне. Мога да редактирам въпроса с примерен код, ако това помогне. - person Dev Kanchen; 16.02.2012

Боже, не вярвам в това.

Проблемите, с които се сблъскахме по-рано с разпределените в стека променливи NSInteger, са валидни, но в този случай вината беше изцяло моя.

„doSomething“ беше част от дълга верига от събития, които, поради някаква глупава небрежност от моя страна, в крайна сметка се повтарят много пъти, което е, което с право и както трябва да бъде, води до изчерпване на паметта на приложението . Независимо дали става дума за променливите на стека или за променливите, които се намират в купчината, с безкраен цикъл, той ще се срине по един или друг начин. :)

Така че сривът е напълно справедлив, просто се обърка в този случай с предишен проблем, който се оказа несвързан. :(

Съжалявам, че губя времето на всички.

person Dev Kanchen    schedule 16.02.2012