2010-09-27 7 views
5

En la documentación para desarrolladores, que dice:¿La mejor manera de drenar periódicamente el grupo de autorrelease en un hilo de fondo de larga duración?

Si la aplicación o el hilo es de larga duración y potencialmente genera una gran cantidad de objetos autoreleased, se debe drenar periódicamente y crear grupos de autorelease (como el Kit de aplicaciones hace en el principal hilo); de lo contrario, los objetos liberados automáticamente se acumulan y su huella de memoria crece. Sin embargo, si su hilo separado no hace llamadas Cocoa, no necesita crear un grupo de liberación automática.

Me preguntaba cuál es la mejor manera de hacerlo. Tengo varios métodos que creo que funcionarían, pero no sé cuál es el "mejor". Actualmente tengo un método que se inicia el hilo y lo mantiene a la espera de operaciones a realizar:

- (void)startThread 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    accessoryRunLoop = [NSRunLoop currentRunLoop]; 

    //Add a dummy port to avoid exiting the thread due to no ports being found 
    [accessoryRunLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; 

    while(accessoryThreadIsRunning) 
    { 
     //Keep the thread running until accessoryTheadIsRunning == NO 
     [accessoryRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
    } 

    [pool release]; 
} 

Mis opciones que se me ocurren son:

1) añadir un contador en el tiempo (accessoryThreadIsRunning) para que cada 50 o 100 veces va a drenar el grupo de autorrelease y crear uno nuevo.

2) Cada vez que realizo un método en ese hilo (usando performSelector: onThread :), puedo crear un grupo de autorrelease y luego soltarlo al final del método.

3) Haga un temporizador para drenar un grupo y luego crearlo periódicamente.

Creo que la opción 1 es la mejor, pero me gustaría saber si hay una manera diferente en que debería estar haciendo esto. ¡Gracias!

+0

Creo que se habló en wwdc 10 sobre eso – RolandasR

Respuesta

4

Comenzaría con dead simple y simplemente crear/drenar el grupo en cada pasada a través del ciclo.

Si aparece durante el análisis de rendimiento como cuello de botella, arréglalo.

Manténgalo simple hasta que el análisis indique que se requiere complejidad.


Acabo de volver a leer su pregunta y me di cuenta de algo completamente absurdo en mi respuesta. Si está ejecutando un ciclo de ejecución, debe administrar automáticamente un grupo de liberación automática; debería crear un grupo en la parte superior del ciclo y drenarlo al final de cada pasada a través del ciclo.

Solo tiene que hacer un ciclo usted mismo si tiene otras cosas fuera del runloop. Es ese el caso?

En cualquier caso, sí, el patrón es:

while(...) { 
    ... create pool ... 
    ... do stuff ... 
    ... drain pool ... 
} 
+0

+1. Autorelease es rápido. http://www.mikeash.com/pyblog/autorelease-is-fast.html – kubi

+0

+1 no olvide que el runloop principal de una aplicación drena el grupo después de cada evento. Si Apple no cree que sea un problema de rendimiento, probablemente no lo sea. – JeremyP

+0

Para que quede claro, debería asignar un nuevo grupo de autorrelease antes del [accessoryRunLoop runMode:] y liberarlo después? Esto está en iPhone, por lo que no es un entorno de GC. – Ned

0

bucle de ejecución del hilo principal drena la piscina en cada pasada, así que tiene sentido hacerlo en otros temas también. Si opta por drenar el pool solo ocasionalmente, corre el riesgo de tener muchos objetos liberados automáticamente esperando ser desasignados por un largo tiempo. De hecho, depende de la cantidad de memoria que puede liberar en cada pasada del ciclo de ejecución y de la frecuencia con la que activa el ciclo de ejecución. Siempre prefiero drenarlo en cada pasada solo porque es fácil y me ayuda a mantener la huella de memoria lo más baja posible.

0

La manera convencional es, sí, para mantener un contador y drenar cada 50 veces o más, pero como dice bbum, simplemente comience drenando la piscina en cada ciclo, y vaya desde allí. O puede -init los objetos que necesita y no crear ningún objeto liberado automáticamente.(simplemente mantente alejado de los métodos de fábrica) Recuerda -release todos tus objetos, sin embargo.

2

Drene cada vez. Como otros han dicho, agotar un grupo de autorrelease es barato.

Además NO drenándolo puede ser muy costoso. Si tiene suficiente material en su pool de autorreleases para causar paginación, usted causa E/S de disco, y la E/S de disco es literalmente miles o millones de veces más costosa que ejecutar un lanzamiento de llamada de lista enlazada. (y en sistemas como iOS que no tienen buscapersonas, muchos objetos adicionales esperando para su liberación automática pueden causarle a la memoria advertencias bajas, lo que podría forzar a las aplicaciones a salir, o la aplicación de primer plano lanzará un montón de vistas de Nib o algo , luego tiene que volver a crearse más tarde ... o podría obligar a su aplicación a salir).

Incluso si no usa memoria extra "suficiente" para causar bajas advertencias de memoria o paginación, se ejecutará una lista de elementos más grande para drenar. Más accesos de memoria estarán entre su último artículo de liberación automática y el más antiguo. Hay una probabilidad mucho mayor de que el elemento de autorrelease más antiguo esté ahora más lejos en la jerarquía de la memoria, por lo que su versión puede tener errores de caché frente a un golpe de caché L1 o L2. Entonces tal vez 100 veces más costoso. Además, la memoria que habría liberado (y podría haber estado caliente en la memoria caché) podría haber sido reutilizada por otro objeto.

Por lo tanto, hacer la liberación automática cada 50 a 100 veces podría no ser una optimización prematura.

Haga una liberación por ciclo, y luego si eso se muestra como un cuello de botella, hágalo cada X veces, y asegúrese de hacerlo más rápido, no más lento.

Cuestiones relacionadas