Comencemos con retain
y release
; autorelease
es realmente solo un caso especial una vez que entiendes los conceptos básicos.
En Cocoa, cada objeto realiza un seguimiento de cuántas veces se hace referencia (específicamente, la NSObject
clase base implementa esto). Al invocar retain
un objeto, le está diciendo que desea aumentar su recuento de referencia en uno. Al llamar release
, le dice al objeto que lo está soltando, y su recuento de referencia disminuye. Si, después de llamar release
, el recuento de referencia ahora es cero, entonces el sistema libera la memoria de ese objeto.
La forma básica en que esto difiere malloc
y free
es que cualquier objeto dado no necesita preocuparse por otras partes del sistema que fallan porque ha liberado la memoria que estaban usando. Suponiendo que todos están jugando y reteniendo / liberando de acuerdo con las reglas, cuando una pieza de código retiene y luego libera el objeto, cualquier otra pieza de código que también haga referencia al objeto no se verá afectada.
Lo que a veces puede ser confuso es conocer las circunstancias bajo las cuales debe llamar retain
y release
. Mi regla general es que si quiero aferrarme a un objeto por un período de tiempo prolongado (por ejemplo, si es una variable miembro en una clase), entonces debo asegurarme de que el recuento de referencias del objeto me conozca. Como se describió anteriormente, el recuento de referencia de un objeto se incrementa al llamar retain
. Por convención, también se incrementa (se establece en 1, realmente) cuando el objeto se crea con un método "init". En cualquiera de estos casos, es mi responsabilidad llamar release
al objeto cuando haya terminado con él. Si no lo hago, habrá una pérdida de memoria.
Ejemplo de creación de objetos:
NSString* s = [[NSString alloc] init]; // Ref count is 1
[s retain]; // Ref count is 2 - silly
// to do this after init
[s release]; // Ref count is back to 1
[s release]; // Ref count is 0, object is freed
Ahora para autorelease
. La liberación automática se usa como una forma conveniente (y a veces necesaria) de decirle al sistema que libere este objeto después de un tiempo. Desde una perspectiva de fontanería, cuando autorelease
se llama, los hilos actuales NSAutoreleasePool
son alertados de la llamada. El NSAutoreleasePool
ahora sabe que una vez que llega una oportunidad (después de la iteración actual del bucle de eventos), se puede llamar release
en el objeto. Desde nuestra perspectiva como programadores, se encarga de llamarnos release
, por lo que no tenemos que hacerlo (y de hecho, no deberíamos).
Es importante tener en cuenta que (de nuevo, por convención) todos los métodos de clase de creación de objetos devuelven un objeto lanzado automáticamente. Por ejemplo, en el siguiente ejemplo, la variable "s" tiene un recuento de referencia de 1, pero una vez que se completa el bucle de eventos, se destruirá.
NSString* s = [NSString stringWithString:@"Hello World"];
Si desea colgarse de esa cadena, deberá llamar retain
explícitamente y luego explícitamente release
cuando haya terminado.
Considere el siguiente bit (muy artificial) de código, y verá una situación en la que autorelease
se requiere:
- (NSString*)createHelloWorldString
{
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
// Now what? We want to return s, but we've upped its reference count.
// The caller shouldn't be responsible for releasing it, since we're the
// ones that created it. If we call release, however, the reference
// count will hit zero and bad memory will be returned to the caller.
// The answer is to call autorelease before returning the string. By
// explicitly calling autorelease, we pass the responsibility for
// releasing the string on to the thread's NSAutoreleasePool, which will
// happen at some later time. The consequence is that the returned string
// will still be valid for the caller of this function.
return [s autorelease];
}
Me doy cuenta de que todo esto es un poco confuso; sin embargo, en algún momento hará clic. Aquí hay algunas referencias para comenzar:
- Introducción de Apple a la gestión de memoria.
- Cocoa Programming para Mac OS X (4a edición) , de Aaron Hillegas, un libro muy bien escrito con muchos ejemplos excelentes. Se lee como un tutorial.
- Si realmente te estás sumergiendo, puedes dirigirte a Big Nerd Ranch . Este es un centro de capacitación dirigido por Aaron Hillegas, el autor del libro mencionado anteriormente. Asistí al curso de Introducción al Cacao allí hace varios años, y fue una excelente manera de aprender.
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
devuelve un objeto lanzado automáticamente (mientras lo escribe), ¿por qué tengo que hacer unreturn [s autorelease];
y configurarlo "lanzamiento automático" nuevamente y no soloreturn s
?[[NSString alloc] initWithString:@"Hello World"]
NO devolverá un objeto lanzado automáticamente. Cada vez quealloc
se llama, el recuento de referencia se establece en 1, y es responsabilidad de ese código asegurarse de que se libere. La[NSString stringWithString:]
llamada, por el contrario, no devolver un objeto autoreleased.Si comprende el proceso de retención / liberación, entonces hay dos reglas de oro que son "duh" obvias para los programadores establecidos de Cocoa, pero desafortunadamente rara vez se explican claramente para los recién llegados.
Si una función que devuelve un objeto tiene
alloc
,create
ocopy
en su nombre, entonces el objeto es suyo. Debe llamar[object release]
cuando haya terminado. OCFRelease(object)
, si es un objeto Core-Foundation.Si NO tiene una de estas palabras en su nombre, entonces el objeto pertenece a otra persona. Debe llamar
[object retain]
si desea conservar el objeto después del final de su función.Le convendría seguir también esta convención en las funciones que cree usted mismo.
(Nitpickers: Sí, desafortunadamente hay algunas llamadas API que son excepciones a estas reglas pero son raras).
fuente
Si está escribiendo código para el escritorio y puede apuntar a Mac OS X 10.5, al menos debería considerar el uso de la recolección de basura Objective-C. Realmente simplificará la mayor parte de su desarrollo, es por eso que Apple puso todo el esfuerzo en crearlo en primer lugar y hacer que funcione bien.
En cuanto a las reglas de administración de memoria cuando no se usa GC:
+alloc/+allocWithZone:
,+new
,-copy
o-mutableCopy
, o si-retain
un objeto, que está tomando posesión de ella y debe asegurarse de que se envíe-release
.-release
.-release
, puede enviarlo usted mismo, o puede enviar el objeto-autorelease
y el grupo de liberación automática actual lo enviará-release
(una vez por recibido-autorelease
) cuando se agote el grupo.Por
-autorelease
lo general, se usa como una forma de garantizar que los objetos vivan durante el evento actual, pero que luego se limpien, ya que existe un grupo de liberación automática que rodea el procesamiento de eventos de Cocoa. En Cocoa, es mucho más común devolver objetos a una persona que llama que se han lanzado automáticamente que devolver objetos que la persona que llama necesita liberar.fuente
Objective-C utiliza el recuento de referencias , lo que significa que cada objeto tiene un recuento de referencias. Cuando se crea un objeto, tiene un recuento de referencia de "1". Simplemente hablando, cuando se hace referencia a un objeto (es decir, se almacena en algún lugar), se "retiene", lo que significa que su número de referencia aumenta en uno. Cuando un objeto ya no es necesario, se "libera", lo que significa que su recuento de referencia se reduce en uno.
Cuando el recuento de referencia de un objeto es 0, el objeto se libera. Este es el recuento de referencia básico.
Para algunos lenguajes, las referencias aumentan y disminuyen automáticamente, pero el objetivo-c no es uno de esos lenguajes. Por lo tanto, el programador es responsable de retener y liberar.
Una forma típica de escribir un método es:
El problema de tener que recordar liberar los recursos adquiridos dentro del código es tedioso y propenso a errores. Objective-C presenta otro concepto destinado a hacer esto mucho más fácil: las agrupaciones de liberación automática. Los grupos de liberación automática son objetos especiales que se instalan en cada subproceso. Son una clase bastante simple, si buscas NSAutoreleasePool.
Cuando un objeto recibe un mensaje de "liberación automática", el objeto buscará cualquier grupo de liberación automática que se encuentre en la pila para este hilo actual. Agregará el objeto a la lista como un objeto para enviar un mensaje de "liberación" en algún momento en el futuro, que generalmente es cuando se libera el grupo.
Tomando el código anterior, puede reescribirlo para que sea más corto y fácil de leer diciendo:
Debido a que el objeto se lanza automáticamente, ya no necesitamos llamarlo explícitamente "release". Esto se debe a que sabemos que algún grupo de liberación automática lo hará por nosotros más tarde.
Espero que esto ayude. El artículo de Wikipedia es bastante bueno sobre el recuento de referencias. Puede encontrar más información sobre las piscinas de liberación automática aquí . También tenga en cuenta que si está compilando para Mac OS X 10.5 y versiones posteriores, puede decirle a Xcode que construya con la recolección de basura habilitada, lo que le permite ignorar por completo la retención / liberación / liberación automática.
fuente
Joshua (# 6591) - El material de recolección de basura en Mac OS X 10.5 parece bastante bueno, pero no está disponible para iPhone (o si desea que su aplicación se ejecute en versiones anteriores a 10.5 de Mac OS X).
Además, si está escribiendo una biblioteca o algo que podría reutilizarse, usar el modo GC bloquea a cualquiera que use el código para que también use el modo GC, por lo que, según tengo entendido, cualquiera que intente escribir código ampliamente reutilizable tiende a administrar memoria de forma manual.
fuente
Como siempre, cuando las personas comienzan a tratar de volver a redactar el material de referencia, casi siempre se equivocan o proporcionan una descripción incompleta.
Apple proporciona una descripción completa del sistema de administración de memoria de Cocoa en la Guía de programación de administración de memoria para Cocoa , al final de la cual hay un resumen breve pero preciso de las Reglas de administración de memoria .
fuente
No agregaré al específico de retención / lanzamiento que no sea que desee pensar en dejar $ 50 y obtener el libro de Hillegass, pero sugeriría encarecidamente que use las herramientas de Instrumentos muy temprano en el desarrollo de su aplicación (incluso su ¡el primero!). Para hacerlo, Ejecutar-> Comenzar con herramientas de rendimiento. Comenzaría con Leaks, que es solo uno de los muchos instrumentos disponibles, pero ayudará a mostrarle cuándo se olvidó de lanzar. Deja de desalentar la cantidad de información que se te presentará. Pero revise este tutorial para levantarse e ir rápido:
TUTORIAL DEL CACAO: FIJACIÓN DE FUGAS DE MEMORIA CON INSTRUMENTOS
En realidad, tratar de forzar las fugas podría ser una mejor manera de aprender a prevenirlas. Buena suerte ;)
fuente
La liberación automática no retiene el objeto. Autorelease simplemente lo pone en cola para ser lanzado más tarde. No desea tener una declaración de lanzamiento allí.
fuente
Mi colección habitual de artículos de gestión de memoria de cacao:
gestión de memoria de cacao
fuente
Hay un screencast gratuito disponible de la red iDeveloperTV
Gestión de memoria en Objective-C
fuente
La respuesta de NilObject es un buen comienzo. Aquí hay información adicional relacionada con la administración manual de memoria ( requerida en el iPhone ).
Si usted personalmente es
alloc/init
un objeto, viene con un recuento de referencia de 1. Usted es responsable de limpiarlo cuando ya no sea necesario, ya sea llamando[foo release]
o[foo autorelease]
. release lo limpia de inmediato, mientras que la liberación automática agrega el objeto al grupo de liberación automática, que lo liberará automáticamente más adelante.la liberación automática es principalmente para cuando tiene un método que necesita devolver el objeto en cuestión ( por lo que no puede liberarlo manualmente, de lo contrario, devolverá un objeto nulo ) pero tampoco desea retenerlo .
Si adquiere un objeto donde no llamó a alloc / init para obtenerlo, por ejemplo:
pero desea aferrarse a este objeto, debe llamar a [foo retener]. De lo contrario, es posible que se obtenga
autoreleased
y se mantenga una referencia nula (como lo haría en elstringWithString
ejemplo anterior ). Cuando ya no lo necesite, llame[foo release]
.fuente
Las respuestas anteriores dan declaraciones claras de lo que dice la documentación; El problema que enfrentan la mayoría de las personas nuevas son los casos indocumentados. Por ejemplo:
Lanzamiento automático : los documentos dicen que activará un lanzamiento "en algún momento en el futuro". ¡¿CUANDO?! Básicamente, puede contar con el objeto alrededor hasta que salga de su código nuevamente en el bucle de eventos del sistema. El sistema PUEDE liberar el objeto en cualquier momento después del ciclo de evento actual. (Creo que Matt dijo eso antes).
Cuerdas estáticas :
NSString *foo = @"bar";
¿tiene que retener o liberar eso? No. ¿Qué tal...
La regla de creación : si la creó, es suya y se espera que la publique.
En general, la forma en que los nuevos programadores de Cocoa se equivocan es al no entender qué rutinas devuelven un objeto con a
retainCount > 0
.Aquí hay un fragmento de Reglas muy simples para la administración de memoria en Cocoa :
La primera viñeta dice: si llamó
alloc
(onew fooCopy
), debe llamar a release en ese objeto.La segunda viñeta dice: si usa un constructor de conveniencia y necesita que el objeto cuelgue (como con una imagen que se dibujará más adelante), debe retenerlo (y luego liberarlo).
El tercero debe explicarse por sí mismo.
fuente
Mucha buena información sobre cocoadev también:
fuente
Como ya mencionaron varias personas, la Introducción a la administración de memoria de Apple es, con mucho, el mejor lugar para comenzar.
Un enlace útil que no he visto mencionado aún es Practical Memory Management . Lo encontrará en el medio de los documentos de Apple si los lee, pero vale la pena vincularlos directamente. Es un resumen ejecutivo brillante de las reglas de administración de memoria con ejemplos y errores comunes (básicamente, lo que otras respuestas están tratando de explicar, pero no tan bien).
fuente