ARC изтичане на памет

Имам изтичане на памет, свързано с NSMutableArray в проект, конфигуриран да използва ARC, който според мен трябваше да се справи с тези неща вместо вас.

Следният код задейства течове на NSNumbers:

NSMutableArray *myArray = [[NSMutableArray alloc] init];

NSNumber  *myNumber = [NSNumber numberWithFloat:10];

[myArray addObject:myNumber];

Изпълнението на последния ред дава следното в програмата за отстраняване на грешки:

objc[1106]: Обект 0x765ffe0 от клас __NSCFNumber е автоматично освободен без пул на място - просто изтича - прекъсване на objc_autoreleaseNoPool() за отстраняване на грешки

Освен това обектът изглежда правилно добавен към променливия масив,

Правя ли нещо очевидно нередно?

Забележка: Има един клас в проекта, който не можах да накарам да работи с ARC, и затова го изключих от ARC, използвайки флага на компилатора -fno-objc-arc. Течовете обаче възникват в други класове, които използват ARC. Не съм сигурен дали това е свързано.

Много благодаря за помощта.


person Spinoxa    schedule 19.03.2012    source източник
comment
Този код изпълнява ли се в отделна нишка? Или в основния метод извън @autoreleasepool контекст?   -  person Richard J. Ross III    schedule 19.03.2012
comment
Единственото споменаване на @autoreleasepool в проекта е в main.m. Кодът за грешка е в други класове. Как мога да проверя дали методът е в отделна нишка? Не съм го пуснал съзнателно в отделна тема, но е възможно това да се е случило. Създадох проекта въз основа на някакъв неофициален примерен код, използващ аудио единици, които намерих онлайн, така че не съм сигурен за всички елементи.   -  person Spinoxa    schedule 19.03.2012
comment
Здравейте, Ричард, течовете СА в отделна нишка спрямо основната, в същата нишка, която изобразява аудио модула, който е класът, изключен от arc. Има ли начин да пренасоча процеса към основната нишка? Или смятате, че трябва да опитам отново да накарам рендирането на аудио модула да работи с ARC? Много благодаря за помощта, мисля, че посочихте вероятната причина!   -  person Spinoxa    schedule 19.03.2012
comment
Предполагам, че друг път, който бих могъл да предприема, е също да изключа проблемните класове от arc, използвайки флага на компилатора, и да правя нещата по старомодния начин. Какво ще ми препоръчате? Нямам опит, така че исках да използвам ARC, ако е възможно...   -  person Spinoxa    schedule 19.03.2012
comment
Просто добавете @autoreleasepool, когато нишката започне да се изпълнява, и трябва да сте добре...   -  person Richard J. Ross III    schedule 19.03.2012
comment
Как мога да намеря точката, в която новата нишка започва да се изпълнява? Как може да изглежда? Първото нещо, което виждам споменато в нишката, е AUIOHelper::NotifyInputAvailable, което предполагам, че е компонент зад кулисите на метода за изобразяване на аудио модул, който е от тип OSStatus. Къде мога да добавя @autoreleasepool? Много благодаря.   -  person Spinoxa    schedule 19.03.2012
comment
Просто добавете пула около всички ваши методи, които се изпълняват в друга нишка.   -  person Richard J. Ross III    schedule 19.03.2012
comment
Направих го! Добавен е @autoreleasepool като първи ред в класа OSStatus и това е спряло течовете!! Много благодаря.   -  person Spinoxa    schedule 19.03.2012


Отговори (2)


Вероятно изпълнявате този код във фонова нишка и нямате въведен пул за автоматично освобождаване. ARC все още ще освобождава автоматично обекти за вас понякога и ако се обаждате на рамки на Apple, те все още може да не са ARC, така че определено могат да бъдат автоматично освобождаващи обекти за вас. Така че все още се нуждаете от пул за автоматично освобождаване.

Cocoa създава пул за автоматично освобождаване за вас в основната нишка, но не прави нищо за вас във фоновите нишки. Ако възнамерявате да хвърлите нещо във фонова нишка, без да използвате NSOperation или нещо подобно, ще искате да обвиете тази нишка в @autoreleasepool, така:

- (void)doSomething {
    [self performSelectorInBackground:@selector(backgroundSomething)];
}

- (void)backgroundSomething {
    @autoreleasepool {
        NSLog(@"Here I am in the background, doing something.");
        myArray = [[NSMutableArray alloc] init];
        // etc.
    }
}
person BJ Homer    schedule 26.03.2012
comment
Благодаря, това наистина беше проблема! - person Spinoxa; 27.03.2012
comment
Отлично, благодаря. Инструментът за течове на инструменти не ги намира, тъй като предполагам, че не са технически течове. - person n13; 20.10.2012
comment
Малко объркващо твърдение относно автоматичното създаване на пул за автоматично освобождаване от Cocoa, вярвам, че работи, защото шаблонът main.m има @autoreleasepool { в int main(. - person A-Live; 09.04.2013
comment
Е, Cocoa също има отделен пул за автоматично освобождаване, който се създава за всяко преминаване на цикъла за изпълнение на основната нишка. - person BJ Homer; 09.04.2013
comment
@BJHomer благодаря за отговора, той ми помогна, но ако - (void)backgroundSomething също се състои от for цикъл, кажете 500 runs, трябва ли да използвам като - (void)backgroundSomething{ for(int i 500 runs){ @autorelease{... nslog(i)}}}... - person maddy; 13.11.2013
comment
@Maddy Ако сте загрижени за натрупването на памет вътре в цикъла for, пул за автоматично освобождаване вътре може да е подходящ. Все още е разумно да имате такъв на основното ниво, само за да избегнете изтичане на информация. Можете да вложите допълнителни пулове за автоматично освобождаване в този, ако желаете. - person BJ Homer; 13.11.2013
comment
какво мога да направя в ситуация като този въпрос stackoverflow.com/questions/21423309/ - person deltaaruna; 05.02.2014
comment
Не разбирам, ако идеята е просто да спам \@autoreleasepool навсякъде, тогава защо това не се прави от компилатора? Ако компилаторът не прави това за всяка нишка автоматично, трябва да има причина понякога да не се поставя \@autoreleasepool там, нали? Кога трябва или не трябва да се поставя \@autoreleasepool в нишка? - person Kevin; 08.12.2014
comment
@Kevin, имате нужда от пул за автоматично освобождаване, ако нишката ще изпълнява Objective-C код и вече не предоставя свои собствени пулове. Пул, който обвива изпълнението на цялата нишка, няма да се източи, докато цялата нишка не завърши; за дълготрайни нишки, които не биха били идеални. Може би е по-добре вместо това да го поставите вътре в цикъл в тялото на цикъл, например, така че да се източва периодично. Поставянето на пула е отговорност на програмиста. - person BJ Homer; 27.12.2014

Много вероятно сте дефинирали NSMutableArray като статична променлива. Когато направите това, попадате извън границите на всеки пул за автоматично освобождаване, тъй като статичните дефиниции се активират извън всеки цикъл на изпълнение. ARC не е магически, той просто автоматизира извикванията за управление на паметта в рамките на съществуващата рамка за запазване/освобождаване и така не може да помогне в тези случаи.

Решението е да инициализирате статичната променлива някъде в клас, така че вашият променлив масив да бъде изграден в рамките на runloop.

person Kendall Helmstetter Gelner    schedule 19.03.2012
comment
Не, статичните променливи не причиняват изтичане на памет, ако го правеха, тогава щях да имам много от тях в текущия си проект, вярвам, че той просто изпълнява код извън контекста на @autoreleasepool. - person Richard J. Ross III; 19.03.2012
comment
Как би изглеждало, ако съм дефинирал NSMutableArray като статична променлива? Трябва ли масивът да бъде деклариран в заглавния файл на класа и с какви свойства? Благодаря - person Spinoxa; 19.03.2012
comment
Не е изтичане на памет. Поне не както повечето хора го определят. Почти единственият начин, който съм срещал на практика за изпълнение на код извън контекста на автоматично освобождаване, е да декларирам NSObject в статична променлива - един случай, който знам, причинява това точно съобщение, е декларирането на статично UIImage с imageNamed в глобална статична променлива. - person Kendall Helmstetter Gelner; 19.03.2012
comment
@Spin: Ще изглежда като статичен NSMutableArray *array = [[NSMutableArray alloc] init], но ще бъде извън блока за изпълнение на класа. Всъщност, дори и да не беше статичен, а просто променлива, декларирана извън имплементацията като глобална, може да причини същия проблем. Виждал съм вашето ТОЧНО съобщение за грешка преди, така че съм по-скоро сигурен, че това е вашият проблем... когато намерите декларацията и я поправите, моля, маркирайте отговора ми като правилен, тъй като ще бъде много забавно отрицателният отговор да бъде маркиран като правилен. - person Kendall Helmstetter Gelner; 19.03.2012
comment
Здравейте Кендъл, благодаря за вашите предложения, но отговорът на Ричард разреши проблема: трябваше да се настрои пул за автоматично освобождаване около вторична нишка. - person Spinoxa; 21.03.2012
comment
Какво общо има runloop с ARC? Освен това този отговор изобщо не отговаря на въпроса. Това е обект, който се освобождава автоматично без пул на място, както се посочва в грешката. - person mattjgalloway; 27.03.2012
comment
Представя отговор на това какъв би могъл да е проблемът, който аз самият видях. Дори и с ARC, ако направите статична UIImage променлива извън който и да е клас и й присвоите екземпляр с imageNamed, ще видите точно същото съобщение. Оставих (очевидно презрения) отговор на място, така че бъдещите потребители на Google да разберат какво не е наред. Някой ще ми благодари, в крайна сметка. - person Kendall Helmstetter Gelner; 27.03.2012
comment
Защото хората са подли и невежи. - person Kendall Helmstetter Gelner; 14.02.2014