Principios básicos de la gestión de memoria en Objective-C / OSX

Gestión de memoria en Objective-C / OSX
La gestión de memoria siempre ha sido un caballo de batalla que los programadores de lenguajes de medio-bajo nivel tenemos que “sufrir”, si bien es cierto que la posibilidad de manejar manualmente la memoria es algo que da flexibilidad a la hora de optimizar un programa, en otros casos suele ser un dolor de cabeza.
Pese a que las nuevas versiones de OSX y Objetive-C han introducido mecanismos de recoleción de basura, se puede decir que Objetive-C es uno de esos lenguajes que nos deja controlar la memoria que ocupamos.
Dado a los avances actuales en las plataformas de programación, uno se puede preguntar para que es necesario controlar manualmente la reserva de memoria. Pese a que los algoritmos que se encargan de “reclamar” la memoria no ocupada cada vez son mejores, no deja de ser un proceso de fondo que se ejecuta con baja prioridad y que recolecta la memoria, dependemos de una tercera parte que vele por nuestra memoria.
Concretamente en el caso de Objective-C, si usamos el recolector de basura, hacemos que nuestro programa sea incompatible con versiones inferiores a la 10.5 (Leopard) que es donde se incluyo por primera vez este módulo. Además si nuestro objetivo es una plataforma como el iPhone donde los recursos son limitados, tampoco contamos con el recolector de basura. A parte de todo esto, desde el punto de vista academico siempre es bueno saber como funcionan las cosas antes de usar los metodos automaticos😉
Una de las claves para la gestión de memoria eficiente es la liberación de la memoria que ya no se utiliza, para ello Objetive-C utiliza un método bastante usado en otros entornos, que es la cuenta de referencias, cuando se crea un objeto en memoria, la cuenta de referencias de dicho objeto se establece en 1, cuando ese objeto se deja de usar se resta esa cuenta, y cuando llega a 0 el objeto se elimina de memoria.
En codigo se utilizan tres mensajes son clave para una primera aproximación, “alloc”, “retain” y “release”.
Cuando construimos un objeto con init, incializamos el contador de referencias, si queremos incrementar el contador de un objeto, le enviariamos en mensaje retain, y cuando queremos decrementar ese contador usariamos release.
Por ejemplo
NSString* cad = [NSString initWithString:@”Probando memoria”]; // Contador de referencias a 1
NSLog(@”%@”, cad);
[cad release]; // Contador de referencias a 0, se elimina el objeto
NSLog(@”%@”, cad); // Error de acceso a memoria, cad ya no existe
Como vemos, el uso es bastante sencillo, veamos ahora un ejemplo en el cual deberiamos usar retain.

La gestión de memoria siempre ha sido un caballo de batalla que los programadores de lenguajes de medio-bajo nivel tenemos que “sufrir”, si bien es cierto que la posibilidad de manejar manualmente la memoria es algo que da flexibilidad a la hora de optimizar un programa, en otros casos suele ser un dolor de cabeza.

Pese a que las nuevas versiones de OSX y Objetive-C han introducido mecanismos de recoleción de basura, se puede decir que Objetive-C es uno de esos lenguajes que nos deja controlar la memoria que ocupamos.

Dado a los avances actuales en las plataformas de programación, uno se puede preguntar para que es necesario controlar manualmente la reserva de memoria. Pese a que los algoritmos que se encargan de “reclamar” la memoria no usada cada vez son mejores, no deja de ser un proceso de fondo que se ejecuta con baja prioridad y que recolecta la memoria, dependemos de una tercera parte que vele por nuestra memoria.

Concretamente en el caso de Objective-C, si usamos el recolector de basura, hacemos que nuestro programa sea incompatible con versiones inferiores a la 10.5 (Leopard) que es donde se incluyo por primera vez este módulo. Además si nuestro objetivo es una plataforma como el iPhone donde los recursos son limitados, tampoco contamos con el recolector de basura. A parte de todo esto, desde el punto de vista academico siempre es bueno saber como funcionan las cosas antes de usar los metodos automaticos😉

La principal tarea para una gestión de memoria eficiente es la liberación de la memoria que ya no se utiliza, para ello Objetive-C utiliza un método bastante usado en otros entornos, dicho método es la cuenta de referencias, cuando se crea un objeto en memoria, la cuenta de referencias de dicho objeto se establece en 1, cuando ese objeto se deja de usar se resta esa cuenta, y cuando llega a 0 el objeto se elimina de memoria.

Para comprender la forma en que se gestiona la memoria en OSX es clave conocer el concepto de propiedad de un objeto.

Como hablamos en el post de los peligros a la  hora de devolver punteros, es el propietario de un objeto quien se hace responsable a la hora de liberarlo de la memoria. El principio básico es: si un objeto te pertenece, liberalo cuando dejes de usarlo, si por otro lado, no te pertenece, no debes liberarlo.

Por tanto la primera pregunta es, ¿Cuando somos dueños de un objeto?, pues principalmente cuando nosotros lo creamos, y esto es cuando usamos una llamada a alloc, algun mensaje que comience por new o que contenga copy.

En código se utilizan tres mensajes que son clave para una primera aproximación, “alloc”, “retain” y “release”.

Cuando construimos un objeto con init, incializamos el contador de referencias, si queremos incrementar el contador de un objeto, le enviariamos en mensaje retain, y cuando queremos decrementar ese contador usariamos release.

Por ejemplo

NSString* cad = [[NSString alloc] initWithString:@"Probando memoria"]]; 
  // Contador de referencias a 1
NSLog(@"%@", cad);
[cad release]; 
  // Contador de referencias a 0, se marca para eliminar el objeto
NSLog(@"%@", cad); 
  // cad ya no se asegura que apunte a un bloque de datos válidos.

Como hemos dicho, el objeto cad nos pertenece ya que lo hemos creado con alloc, asi que lo correcto es enviar al objeto el mensaje de release cuando ya no vamos a seguir usandolo.

Seguramente ya sabemos que hay otros métodos para obtener referencias a un objeto, por ejemplo:

NSString *cad = [NSString stringWithString:@"Hola"];
[cad release] // Error, el objeto no es nuestro

En este caso, el objeto no nos pertenece, por lo que no deberiamos liberarlo cuando dejemos de usarlo.

Para explicar este funcionamiento, es necesario conocer lo que se llama Autorelease Pool. En el caso anterior, en objeto no nos pertenece, pero se tiene que liberar de alguna manera, ahi es donde entra el autorelease pool, dicha funcionalidad se encargará de llamar al mensaje release de todos los objetos que estan en dicho pool cuando estos salgan fuera de ambito, o cuando le enviemos el mensaje drain al propio pool.

Supongamos el ejemplo:

- (NSString* ) getString ()
{
	NSString *result = [[NSString alloc] initWithString:@"prueba"]
	[result autorelease];
	return result;
}
...
NSString *cad = [objeto getString];

Ya que obtenemos el objeto cad, mediante un método que no transfiere la propiedad, el objeto se liberará cuando salga fuera de ambito. En el caso de Cocoa, se crea un pool justo antes de procesar un evento y se llama a drain justo cuando finaliza este evento.

Esta forma de gestionar el pool puede llegar a producir algun problema, ya que si queremos que un objeto que esta en el pool sobreviva a diferentes eventos, debemos enviarle el mensaje retain antes de que termine el evento, de otra manera, el objeto se destruirá.

Como hemos visto los conceptos básicos de la gestión de memoria en OSX son sencillos, pero es importante usarlos de forma correcta para evitar problemas cuando desarrollamos nuestra aplicacion para iPhone o en Cocoa.

2 respuestas a Principios básicos de la gestión de memoria en Objective-C / OSX

  1. […] igual que mencionamos en el otro post de gestión de memoria en OSX, estos mecanismos, gracias al uso del garbage collector estan pasando a ser cosa del pasado. Ya que […]

  2. My brother suggested I might like this web site.

    He was entirely right. This post actually made my day.
    You cann’t imagine simply how much time I had spent for this info! Thanks!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: