5

Aplikacja, nad którą pracuję, gromadzi coraz więcej pamięci w miarę upływu czasu. To naprawdę nie jest wyciek pamięci, ponieważ narzędzie Leaks nie rozpoznaje go jako wycieku, ale jest to coś, co ciągle zabiera coraz więcej pamięci.Co zrobić, gdy "wycieki pamięci" są spowodowane przez strukturę Foundation?

Używam instrumentów (narzędzie alokacji pamięci), aby dowiedzieć się, dlaczego tak się dzieje, a teraz robię migawki, aby znaleźć różnice w pamięci między różnymi punktami w bieżącym cyklu. Wydaje się, że po każdym cyklu ilość pamięci wzrasta o około 560 KB.

Jak to wygląda w narzędziu instrumenty:

Instruments initial

A przy wyborze wiersza CFString:

CFString allocation

Pełne Śledzenie stosu z prawej wygląda to:

0 CoreFoundation _CFRuntimeCreateInstance 
    1 CoreFoundation __CFStringCreateImmutableFunnel3 
    2 CoreFoundation CFStringCreateWithBytes 
    3 Foundation -[NSString initWithCoder:] 
    4 Foundation _decodeObject_old 
    5 SyncServices -[ISDProperty initWithCoder:] 
    6 SyncServices -[ISDRelationship initWithCoder:] 
    7 Foundation _decodeObject_old 
    8 Foundation _decodeValueOfObjCType 
    9 Foundation -[NSUnarchiver decodeValueOfObjCType:at:] 
    10 Foundation -[NSArray(NSArray) initWithCoder:] 
    11 Foundation _decodeObject_old 
    12 SyncServices -[ISDEntity initWithCoder:] 
    13 Foundation _decodeObject_old 
    14 Foundation _decodeValueOfObjCType 
    15 Foundation -[NSUnarchiver decodeValueOfObjCType:at:] 
    16 Foundation -[NSArray(NSArray) initWithCoder:] 
    17 Foundation _decodeObject_old 
    18 SyncServices -[ISDRelationship initWithCoder:] 
    19 Foundation _decodeObject_old 
    20 Foundation _decodeValueOfObjCType 
    21 Foundation -[NSUnarchiver decodeValueOfObjCType:at:] 
    22 Foundation -[NSArray(NSArray) initWithCoder:] 
    23 Foundation _decodeObject_old 
    24 SyncServices -[ISDEntity initWithCoder:] 
    25 Foundation _decodeObject_old 
    26 Foundation _decodeValueOfObjCType 
    27 Foundation -[NSUnarchiver decodeValueOfObjCType:at:] 
    28 Foundation -[NSArray(NSArray) initWithCoder:] 
    29 Foundation _decodeObject_old 
    30 SyncServices -[ISDRelationship initWithCoder:] 
    31 Foundation _decodeObject_old 
    32 Foundation _decodeValueOfObjCType 
    33 Foundation -[NSUnarchiver decodeValueOfObjCType:at:] 
    34 Foundation -[NSArray(NSArray) initWithCoder:] 
    35 Foundation _decodeObject_old 
    36 SyncServices -[ISDEntity initWithCoder:] 
    37 Foundation _decodeObject_old 
    38 Foundation _decodeValueOfObjCType 
    39 Foundation -[NSUnarchiver decodeValueOfObjCType:at:] 
    40 Foundation -[NSArray(NSArray) initWithCoder:] 
    41 Foundation _decodeObject_old 
    42 SyncServices -[ISDRelationship initWithCoder:] 
    43 Foundation _decodeObject_old 
    44 Foundation _decodeValueOfObjCType 
    45 Foundation -[NSUnarchiver decodeValueOfObjCType:at:] 
    46 Foundation -[NSArray(NSArray) initWithCoder:] 
    47 Foundation _decodeObject_old 
    48 SyncServices -[ISDEntity initWithCoder:] 
    49 Foundation _decodeObject_old 
    50 Foundation +[NSUnarchiver unarchiveObjectWithData:] 
    51 SyncServices -[ISDObjectGraphWrapper initWithCoder:] 
    52 Foundation -[NSKeyedPortCoder decodeObjectForKey:] 
    53 Foundation -[NSArray(NSArray) initWithCoder:] 
    54 Foundation -[NSKeyedPortCoder decodeObjectForKey:] 
    55 Foundation -[NSKeyedPortCoder _decodeObjectNoKey] 
    56 Foundation -[NSKeyedPortCoder _walkAndDecodeDataWithType:at:chase:invocation:inStructure:] 
    57 Foundation decodeInvocationArguments 
    58 Foundation -[NSKeyedPortCoder decodeInvocation] 
    59 Foundation -[NSKeyedPortCoder decodeObjectForKey:] 
    60 Foundation -[NSConnection handleRequest:sequence:] 
    61 Foundation -[NSConnection handlePortCoder:] 
    62 Foundation -[NSConnection dispatchWithComponents:] 
    63 Foundation __NSFireMachPort 
    64 CoreFoundation __CFMachPortPerform 
    65 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ 
    66 CoreFoundation __CFRunLoopDoSource1 
    67 CoreFoundation __CFRunLoopRun 
    68 CoreFoundation CFRunLoopRunSpecific 
    69 Foundation -[NSRunLoop(NSRunLoop) runMode:beforeDate:] 
    70 SyncServices -[ISyncConcreteSession _waitForTransitionFromPhase:untilDate:] 
    71 SyncServices +[ISyncSession _sessionWithClient:entityNames:beforeDate:clientHasTruthForEntityNames:quietlyPushTruth:target:selector:anchors:hasChanges:skip:error:] 
    72 SyncServices +[ISyncSession beginSessionWithClient:entityNames:beforeDate:] 
    73 SyncServices -[ISyncConcreteSessionDriver _beginSyncSession:] 
    74 SyncServices -[ISyncConcreteSessionDriver _preSync] 
    75 SyncServices -[ISyncConcreteSessionDriver _sync:] 
    76 SyncServices -[ISyncConcreteSessionDriver sync] 
    77 **Our application** - [SLSyncOperation performLocalSync] /Users/andrei/Desktop/MacOSX_Client/osx/Classes/SLSyncOperation.m:94 
    78 **Our application** -[SLSyncOperation main] /Users/andrei/Desktop/MacOSX_Client/osx/Classes/SLSyncOperation.m:251 
    79 Foundation -[__NSOperationInternal start] 
    80 Foundation ____NSOQSchedule_block_invoke_2 
    81 libdispatch.dylib _dispatch_call_block_and_release 
    82 libdispatch.dylib _dispatch_worker_thread2 
    83 libsystem_c.dylib _pthread_wqthread 
    84 libsystem_c.dylib start_wqthread 

Używam SyncServices w celu uzyskania informacji kontaktowych. Używam ISyncSessionDriver do sprawdzania (synchronizowania) nowych informacji w określonym przedziale czasu (10 sekund, można to również zobaczyć na obrazie z alokacją pamięci). Kod wygląda tak.

SLSyncSessionDriverDataSource *dataSource = [[SLSyncSessionDriverDataSource alloc] initWithManagedObjectModel:managedObjectModel context:managedObjectContext]; 

ISyncSessionDriver *localDriver = [ISyncSessionDriver sessionDriverWithDataSource:dataSource]; 
SLSyncSessionDriverDelegate *theDelegate = [[SLSyncSessionDriverDelegate alloc] init]; 
[localDriver setDelegate:theDelegate]; 

[theDelegate release]; 
[dataSource release];  

[localDriver sync]; 

Dzięki za pomoc, jaką możesz mi dać!

Odpowiedz

2

Zakładając, że znalazłeś prawdziwy przeciek, kilka pomysłów:

  • można uruchomić tylko synchronizację, gdy pojawia się prawdopodobnie nowy informacje (obserwować zmiany w ~/Library/Application Support/AddressBook z KQUEUE lub FSEvents).

  • Można uruchomić synchronizację procesu podrzędnego, który jest okresowo przetwarzany, lub z poprzednią sugestią, wystarczy jeden proces, zrób synchronizację, a następnie zakończ.

Usługi synchronizacji nigdy nie działały strasznie dobrze i są przestarzałe od 10,7, więc wyobrażam sobie, że nie zobaczą wiele, jeśli będą jakąkolwiek dodatkową pracą. Nie sądzę, że byłoby stratą czasu wymyślić samodzielny przykład i submit it as a bug, zwłaszcza jeśli jest to bardzo nieszczelne. Sugeruję także zgłoszenie innego błędu w strukturze Książki adresowej wyjaśniającego, że chcesz sprawdzić/otrzymać powiadomienia o nowych/zaktualizowanych informacjach.

+0

Dzięki za odpowiedź. fork (tworzenie procesu potomnego) nie wydaje się działać dobrze na OSX, szczególnie w aplikacji korzystającej z innych frameworków. Próbowałem FSEvents i to działało całkiem nieźle. W końcu lepiej przyjrzałem się kodowi i zorientowałem się, że to była * zmienna instancji *, która to spowodowała. Poświęciłbym na to pamięć raz za razem bez zwalniania. Po zwolnieniu go działa dobrze. Interesujące było to, że XCode Analyzer nie zarejestrował tego, co robiłem jako potencjalny wyciek pamięci. – Andrei

+0

Cieszę się, że to wymyśliłeś! Tak, nie możesz się rozwidlać, gdy robisz graficzne rzeczy, ale istnieją inne sposoby (np. NSWorkspace lub Launch Services są wysokimi poziomami, są niższe poziomy), aby uruchomić aplikacje pomocnicze. Na Lion możesz również spojrzeć na usługi XPC. –

Powiązane problemy