Jak rozumiem, wszystko, co zostało utworzone za pomocą alokacji , nowego lub kopii, musi zostać ręcznie zwolnione. Na przykład:
int main(void) {
NSString *string;
string = [[NSString alloc] init];
/* use the string */
[string release];
}
Moje pytanie brzmi jednak, czy nie byłoby to równie ważne ?:
int main(void) {
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
[pool drain];
}
objective-c
memory-management
nsautoreleasepool
foundationkit
James Sumners
źródło
źródło
an object
powinno byćan object that is a subclass of NSObject or NSProxy and doesn't override -autorelease
.NSAutoreleasePool: dren vs. release
Ponieważ funkcja
drain
irelease
wydaje się powodować zamieszanie, warto tutaj wyjaśnić (chociaż jest to omówione w dokumentacji ...).Ściśle mówiąc, z szerszej perspektywy nie
drain
jest to równoznaczne zrelease
:W środowisku zliczanym referencjami
drain
wykonuje te same operacje, corelease
, więc oba są w tym sensie równoważne. Aby podkreślić, oznacza to, że nie przeciekasz basenu, jeśli używaszdrain
zamiastrelease
.W środowisku zbierania śmieci
release
nie ma możliwości. Zatem nie ma to żadnego skutku.drain
z drugiej strony zawiera wskazówkę dla zbieracza, że powinien „zbierać w razie potrzeby”. Tak więc w środowisku zbierania śmieci używaniedrain
pomaga systemowi zrównoważyć proces zbierania danych.źródło
NSAutoreleasePool
. Dzieje się tak, ponieważ pule działają jak stos. Utworzenie wystąpienia puli powoduje wypychanie tej puli na szczyt stosu puli autowyrejestrowywania wątków.-release
powoduje, że pula ta wyskakuje ze stosu ORAZ wszystkie pule, które zostały na nią odłożone, ale z jakiegoś powodu nie zostały zdeponowane.Jak już wspomniano, drugi fragment kodu jest poprawny.
Chciałbym zasugerować bardziej zwięzły sposób korzystania z puli autowydzielania, która działa we wszystkich środowiskach (liczenie referencji, GC, ARC), a także pozwala uniknąć zamieszania:
W powyższym przykładzie zwróć uwagę na blok @autoreleasepool . Jest to udokumentowane tutaj .
źródło
@autoreleasepool
bloku z ARC.Nie, mylisz się. Dokumentacja jasno stwierdza, że w trybie non-GC -drain jest równoważne -release, co oznacza, że pakiet NSAutoreleasePool nie zostanie ujawniony.
źródło
NSAutoreleasePool
: developer.apple.com/mac/library/documentation/Cocoa/Conceptual/…Co przeczytałem z Apple: „Pod koniec bloku puli autowyzwolenia obiekty, które otrzymały wiadomość o autowyznoszeniu w ramach bloku, otrzymują komunikat o zwolnieniu - obiekt otrzymuje komunikat o zwolnieniu za każdym razem, gdy został wysłany w ramach bloku. "
https://developer.apple.com/library/mac/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html
źródło
wysłanie autorelease zamiast zwolnienia do obiektu wydłuża żywotność tego obiektu przynajmniej do momentu opróżnienia samej puli (może to być dłuższe, jeśli obiekt zostanie później zachowany). Obiekt można umieścić w tej samej puli kilka razy, w takim przypadku otrzymuje komunikat o zwolnieniu za każdym razem, gdy został umieszczony w puli.
źródło
Tak i nie. Skończyło się na zwolnieniu pamięci ciągu, ale „wyciekaniu” obiektu NSAutoreleasePool do pamięci przez użycie drenu zamiast zwolnienia, jeśli uruchomiono to w środowisku zbierania elementów bezużytecznych (bez zarządzania pamięcią). Ten „wyciek” po prostu sprawia, że wystąpienie NSAutoreleasePool jest „nieosiągalne”, jak każdy inny obiekt bez silnych wskaźników w GC, a obiekt zostałby wyczyszczony przy następnym uruchomieniu GC, co może być bezpośrednio po wywołaniu
-drain
:W przeciwnym razie jest to podobne do tego, jak
-release
zachowuje się pod nie-GC, tak. Jak powiedzieli inni, nie-release
działa w GC, więc jedynym sposobem, aby upewnić się, że pula działa poprawnie w GC, jest przejście-drain
, a-drain
pod non-GC działa dokładnie tak, jak-release
w przypadku innego niż GC i prawdopodobnie lepiej komunikuje swoją funkcjonalność, ponieważ dobrze.Powinienem zwrócić uwagę, że twoje oświadczenie "wszystko wywołane z new, przydziel lub init" nie powinno zawierać "init" (ale powinno zawierać "copy"), ponieważ "init" nie alokuje pamięci, a jedynie ustawia obiekt (konstruktor moda). Jeśli otrzymałeś przydzielony obiekt, a twoja funkcja wywołałaby tylko init jako taką, nie zwolniłbyś jej:
To nie zużywa więcej pamięci niż ta, od której już zacząłeś (zakładając, że init nie tworzy instancji obiektów, ale i tak nie jesteś za nie odpowiedzialny).
źródło
-[NSAutoreleasePool release]
w środowisku, w którym zbierane są elementy bezużyteczne.-[NSAutoreleasePool drain]
działa zarówno w środowiskach zliczanych odwołań, jak i ze śmieciami.