2009-04-17 7 views
5

Estoy trabajando en rastrear algunas fugas de memoria difíciles de encontrar en mi programa de iPhone. Estoy corriendo una prueba rápida en una aplicación que se escapa un objeto NSString con el siguiente código intencionadamente -incorrect-:Dando sentido a la utilidad de línea de comandos de "fugas" para encontrar fugas de memoria

-(void)applicationDidFinishLaunching:(NSNotification *)notification; 
{ 
    NSMutableString *test = [[NSMutableString alloc] init]; 
    [test appendString:@"Testing 1"]; 
    [test appendString:@"\nTesting 2"]; 
    NSLog(@"%@", test); 

    // Uncomment the following line to release the 
    // string and clean up your leak. 
    // [test release], test = nil; 
} 

Después de ejecutar las fugas en el identificador de proceso de la aplicación, se me ocurre lo siguiente:

sf$ leaks 3951 
Process 3951: 9988 nodes malloced for 1260 KB 
Process 3951: 3 leaks for 128 total leaked bytes. 
Leak: 0x163b50 size=64 instance of 'NSCFDictionary', type ObjC, implemented in Foundation 
    0xa07e0720 0x01001080 0x0000000a 0x00000010  .~............. 
    0x0000000a 0x0000000c 0x0000000b 0x00000000  ................ 
    0x00000000 0x00000015 0xa1b1c1d3 0x00163b90  .............;.. 
    0x00163bd0 0x00000000 0x00000000 0x00000000  .;.............. 
Leak: 0x178190 size=32 string 'Testing 1 
Testing 2' 
Leak: 0x178210 size=32 instance of 'NSCFString', type ObjC, implemented in CoreFoundation 
    0xa02e24a0 0x010007ad 0x00178190 0x00000013  .$.............. 
    0x00000020 0x00000200 0x00000000 0x00000000  ............... 

Ahora, todos sabemos dónde está la fuga. Ese no es el objetivo de este ejercicio, al menos para mí. Estoy tratando de reconocer cómo dar sentido a esta salida. Me dicen que hay 3 filtraciones.

Son objetos que se encuentran en las direcciones de memoria 0x163b50, 0x178190, 0x178210. Su implementación está en los marcos de Apple, no en mi código, de acuerdo con "filtraciones". En un ejemplo trivial como el siguiente, encontrar la fuga no es difícil. Sin embargo, en una aplicación con 500K líneas de código, encuentro que la salida de fugas aquí es inútil.

¿Qué estoy haciendo mal y cómo puedo dar sentido a esta salida para ayudarme a encontrar el culpable en el código que he escrito para limpiar mis pérdidas de memoria?

Tenga en cuenta que este hilo no debe recomendar el uso de Instruments o Clang Static Analyzer. Limpié todas las pérdidas de memoria que Clang Static Analyzer me informó. Los instrumentos están hinchados y no son informativos para mí. Recibo muchísimos informes de filtraciones, ninguno de los cuales los rastros de la pila muestran se remontan a mi propio código, aunque estoy seguro de que la (s) fuga (s) está (n) en mi código. Me gustaría descubrir cómo usar la herramienta de fugas de línea cmd aquí.

Gracias a todos.

EDIT: Incluso después de descomentar las líneas para limpiar las fugas, la utilidad 'fugas' se queja aún más de lo que lo hacía cuando había fugas. ¿Se está filtrando Foundation/Cocoa desde un ejemplo tan trivial? Esto se produce después descomentando la liberación de la cadena de prueba de arriba:

sf$ leaks 4383 
Process 4383: 9890 nodes malloced for 1255 KB 
Process 4383: 7 leaks for 560 total leaked bytes. 
Leak: 0x163920 size=176 instance of 'NSPathStore2', type ObjC, implemented in Foundation  
    0xa07e2ae0 0x04f00000 0x0055002f 0x00650073  .*~...../.U.s.e. 
    0x00730072 0x0073002f 0x002f0066 0x0069004c  r.s./.s.f./.L.i. 
    0x00720062 0x00720061 0x002f0079 0x00700041  b.r.a.r.y./.A.p. 
    0x006c0070 0x00630069 0x00740061 0x006f0069  p.l.i.c.a.t.i.o. 
    0x0020006e 0x00750053 0x00700070 0x0072006f  n. .S.u.p.p.o.r. 
    0x002f0074 0x00490053 0x0042004d 0x002f004c  t./.S.I.M.B.L./. 
    0x006c0050 0x00670075 0x006e0069 0x002f0073  P.l.u.g.i.n.s./. 
    0x00650054 0x006d0072 0x006e0069 0x006c0061  T.e.r.m.i.n.a.l. 
    ... 
Leak: 0x163350 size=160 instance of 'NSPathStore2', type ObjC, implemented in Foundation  
    0xa07e2ae0 0x04a00000 0x0055002f 0x00650073  .*~...../.U.s.e. 
    0x00730072 0x0073002f 0x002f0066 0x0069004c  r.s./.s.f./.L.i. 
    0x00720062 0x00720061 0x002f0079 0x00700041  b.r.a.r.y./.A.p. 
    0x006c0070 0x00630069 0x00740061 0x006f0069  p.l.i.c.a.t.i.o. 
    0x0020006e 0x00750053 0x00700070 0x0072006f  n. .S.u.p.p.o.r. 
    0x002f0074 0x00490053 0x0042004d 0x002f004c  t./.S.I.M.B.L./. 
    0x006c0050 0x00670075 0x006e0069 0x002f0073  P.l.u.g.i.n.s./. 
    0x00650044 0x0069006c 0x00690063 0x0075006f  D.e.l.i.c.i.o.u. 
    ... 
Leak: 0x1635a0 size=64 instance of 'NSCFDictionary', type ObjC, implemented in Foundation 
    0xa07e0720 0x01001080 0x0000000a 0x00000010  .~............. 
    0x0000000a 0x0000000c 0x0000000b 0x00000000  ................ 
    0x00000000 0x00000015 0xa1b1c1d3 0x001635e0  .............5.. 
    0x00163620 0x00000000 0x00000000 0x00000000  6.............. 
Leak: 0x163620 size=64 
    0xa02ed360 0x00160ee0 0x00163700 0xa02efc00  `........7...... 
    0x00000000 0x00000000 0x00163680 0x00000000  .........6...... 
    0x00000000 0x00000000 0x00163660 0xa02ed440  ........`[email protected] 
    0xa02ec1a0 0xa02f0420 0x00000000 0x00163660  .... ./.....`6.. 
Leak: 0x163680 size=48 instance of 'NSCFString', type ObjC, implemented in CoreFoundation 
    0xa02e24a0 0x0100078c 0x6d6f6323 0x6c65642e  .$......#com.del 
    0x6f696369 0x61737375 0x69726166 0x6c65442e  icioussafari.Del 
    0x6f696369 0x61537375 0x69726166 0x00000000  iciousSafari.... 
Leak: 0x163660 size=32 instance of 'NSCFString', type ObjC, implemented in CoreFoundation 
    0xa02e24a0 0x0200078c 0x6c65440f 0x6f696369  .$.......Delicio 
    0x61537375 0x69726166 0x00000000 0x00000000  usSafari........ 
Leak: 0x160ee0 size=16 instance of 'NSCFString', type ObjC, implemented in CoreFoundation 
    0xa02e24a0 0x0100078c 0x362e3103 0x00000000  .$.......1.6.... 
+0

¿es esta una aplicación Mac o una aplicación para iPhone? ¿Puedes usar el binario de fugas del Mac en el iphone? –

Respuesta

4

No hay ningún rastro de pila en la salida que mostró. Las direcciones que ve son las direcciones propias de los objetos, no los punteros de función, y los números hexadecimales junto a los caracteres de puntuación son simplemente el volcado hexadecimal de los datos.

Para localizar el origen del objeto se asignó de, establece MallocStackLogging en el entorno de fugas:

% MallocStackLogging=1 leaks … 

También puede que quiera usar la opción -nocontent, que suprime el volcado hexadecimal. No use esto todo el tiempo, sin embargo: a veces el volcado hexadecimal contiene una pista valiosa.

Además, las filtraciones no necesariamente le dicen que tiene tres fugas; para ser precisos, le dice que tiene tres objetos filtrados. La fuga deliberada que mostró solo produce un objeto filtrado, pero una fuga diferente (como en un bucle o un método llamado con frecuencia) puede filtrar muchos objetos.

Edit: Por cierto, algunas de esas fugas son de SIMBL o uno o más de sus SIMBL plug-ins. Desactiva SIMBL y cualquier otro administrador de entrada piratea antes de buscar fugas. Recuerde, ese código se ejecuta en su proceso; además, a las fugas no le importa qué código asignó o filtró la memoria, solo que se filtró, por lo que mostrará el objeto filtrado independientemente de quién lo haya asignado o filtrado.

+0

Gracias Peter. No tengo idea con SIMBL, pero lo buscaré. –

1

Para este ejemplo, las fugas de informes 3 fugas para un total de 128 bytes. La interpretación debe ser el siguiente:

1) se filtra la una NSMutableString que parece estar implementado internamente como NSCFDictionary para un total de 64 bytes

2) se filtra la Prueba 1 para un total de 32 bytes

3) se filtra la \ nTesting 2 para un total de 32 bytes

esto debe ser porque si no lo suelte NSMutableString, ninguno de los objetos (cadenas en este caso) que pertenece a la estructura de datos NSCFDictionary se liberarse: se retienen cada vez que utiliza el método appendString. Cuando suelta su NSMutableString, todos los objetos dentro de NSCFDictionary se liberan automáticamente, junto con el propio NSCFDictionary.

A partir de la documentación de Apple (http://developer.apple.com/iPhone/library/documentation/Performance/Conceptual/ManagingMemory/Articles/FindingLeaks.html):

Si un objeto de cacao se autoreleased sin piscina autorelease en su lugar, Xcode envía un mensaje a la consola que le advierte que el objeto es simplemente una fuga. Incluso si no está escribiendo una aplicación Cocoa, es posible ver este mismo tipo de advertencia de consola.La implementación de muchas clases de Cocoa se basa en los tipos de Foundation Core. Si su aplicación usa Core Foundation, es posible que las filtraciones ocurran como resultado de llamadas a ese marco.

Para encontrar fugas de memoria de este tipo, use el depurador para poner un punto de interrupción en la función _NSAutoreleaseNoPool. Esta función se declara en NSDebug.h en el marco de Foundation. Cuando el depurador alcance esa función, debería poder ver el rastreo de la pila y ver qué parte del código causó la fuga.

2

Creo que la razón por la que está viendo esto en fugas es porque appendString está usando autorelease internamente. El grupo de autorrelease no se descarta hasta el próximo 'evento'. Básicamente, creo que la muestra es demasiado simple para mostrar con precisión lo que está sucediendo.

Podría estar fuera de la base aquí, pero trataría de envolver su código en un grupo de liberación automática para ver qué cambios.

-(void)applicationDidFinishLaunching:(NSNotification *)notification; 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSMutableString *test = [[NSMutableString alloc] init]; 
    [test appendString:@"Testing 1"]; 
    [test appendString:@"\nTesting 2"]; 
    NSLog(@"%@", test); 
    [test release], test = nil; 
    [pool release] // this should drain the autorelease pool 
}