2014-04-30 44 views
5

Utwórz nowy projekt ARC i wprowadź ten kod w didFinishLaunchingWithOptions.NSNumber możliwy wyciek pamięci

for (int i=0; i < 1000000; i++) { 
    NSNumber* num = [NSNumber numberWithInt:i]; 
    NSLog(@"%@", num); 
} 

NSLog(@"over"); 

Pamięć aplikacji zwiększy się. Również na końcu pętli for pamięć nie zmniejszy się.

Jednakże, jeśli w tym samym zastąpić pętli:

NSNumber* num = [NSNumber numberWithInt:i]; 

przez

NSNumber* num = [[NSNumber alloc] initWithInt:i]; 

Następnie pamięć pozostanie stabilny.

Czy to oczekiwane zachowanie?

EDIT:

Ok, więc postawmy didFinishLaunchingWithOptions na stronie w tej chwili. Nadal można umieścić viewDidLoad i usunąć zero, aby dotrzeć do końca pętli for. Pamięć aplikacji będzie rosnąć do ~ 11 MB. Po zakończeniu pętli for pamięć NIE zostanie zmniejszona. Pozostaje około ~ 11 MB.

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    for (int i=0; i < 100000; i++) { 
     NSNumber* num = [NSNumber numberWithInt:i]; 
     NSLog(@"%@", num); 
    } 

    NSLog(@"over"); 
} 

Jeśli się z:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    @autoreleasepool { 
     for (int i=0; i < 100000; i++) { 
      NSNumber* num = [NSNumber numberWithInt:i]; 
      NSLog(@"%@", num); 
     } 
    } 

    NSLog(@"over"); 
} 

Niespodzianka! Niespodzianka! Będziesz mieć dokładnie takie samo zachowanie. Osiągniesz rozmiar około 11 MB, a pamięć NIE zostanie zmniejszona. Jednak wstawienie @autorelease w pętli zadziała ... Ale tutaj, nie próbuję działać, ale rozumiem, dlaczego pamięć nie jest wyczerpana na końcu pętli for.

Pytanie jest więc nadal otwarte.

+0

Ciekawe .. Czekam na opinie specjalistów na ten jeden .. – rdurand

+0

Co jeśli umieścić '@autoreleasepool {...}' 'wokół for' stwierdzeniem? – trojanfoe

+0

Czy próbowałeś z innymi lekcjami Foundation? Co powiesz na init z innym typem (initWithBool: na przykład)? – rdurand

Odpowiedz

3

To jest oczekiwane. Po przydzieleniu NSNumber przy pomocy alloc/init, ARC zwolni go, gdy tylko nie będzie już potrzebny.

Po przydzieleniu go za pomocą wygodnej metody, takiej jak numberWithInt:, otrzymasz obiekt przydzielony w puli autorelease. Dopóki pula autorelease nie zostanie wyczerpana, pamięć nie zostanie zwolniona. Można jednak utworzyć pulę autorelease dla tej pętli:

for (int i=0; i < 1000000; i++) @autoreleasepool { 
    NSNumber* num = [NSNumber numberWithInt:i]; 
    NSLog(@"%@", num); 
} 

NSLog(@"over"); 

Powinno to zwolnić liczbę po każdej iteracji wyglądu.

można uzyskać dalsze szczegóły tutaj: Memory Management Policy

+1

To nie może być powód. Główny wątek ma już pulę autorelease, która jest opróżniana na każdym przeskoku kadru. Numery te zostaną zwolnione chwilę po 'application: didFinishLaunchingWithOptions:' exit. – hamstergene

+0

@trojanfoe tak, będzie. – Jorge

+0

Rzeczywiście. Nietypowa składnia. – trojanfoe