¿Está bien usar malloc()/free() “clásico” en las aplicaciones de Objective-C/iPhone?

9 minutos de lectura

avatar de usuario
Felipe Leybaert

He estado jugando con el desarrollo de iPhone por un tiempo, y aunque se siente un poco incómodo cuando eres un desarrollador de .NET “hardcore”, no es tan malo una vez que te acostumbras.

En cada libro que leo sobre Objective-C, solo se habla de retain/release (recuento de referencias) para la gestión de la memoria. Como desarrollador de C/C++ de la vieja escuela, parece extraño que asignar la forma “normal”, usando malloc() y free() sólo se menciona en algunas notas a pie de página.

Yo sé eso malloc() y free() trabajar en Objective-C, pero tengo curiosidad si es una práctica común o no. Después de todo, si quiero asignar una matriz de 100 enteros, parece que esta es la forma más eficiente de hacerlo:

int *array = malloc(sizeof(int) * 100);

memset(array,0,sizeof(int) * 100);

// use the array

free(array);

¿Es esta realmente la mejor manera, o debería evitar la administración de memoria C simple?

Hay un envoltorio de Objective-C alrededor de la memoria sin procesar que me gusta usar mucho para tareas similares: NSMutableData. Tiene la ventaja de permitirle retener/liberar la propiedad y además puede hacer crecer la matriz fácilmente (sin tener que realizar la reasignación usted mismo).

Su código se vería así:

NSMutableData* data = [NSMutableData dataWithLength:sizeof(int) * 100];
int* array = [data mutableBytes];
// memory is already zeroed

// use the array

// decide later that we need more space:
[data setLength:sizeof(int) * 200];
array = [data mutableBytes]; // re-fetch pointer in case memory needed to be copied

// no need to free
// (it's done when the autoreleased object is deallocated)

  • Me gusta esta respuesta @Nikolai Ruhe. Estaba usando una matriz “mallocada” como propiedad. Tenía 3 objetos de esta clase y “liberé” la matriz en dealloc. Sin embargo, después de liberar el primer objeto, recibí un error “malloc: *** error para el objeto 0x70a60: el puntero que se estaba liberando no se asignó” al liberar el segundo. Parece que el malloc se realizó a “nivel de clase”, en lugar de “nivel de objeto”. Cambiar a su solución hizo que esto desapareciera, pero el “comportamiento” de los objetos también cambió. Aún no estoy seguro de por qué.

    – Desarrollador iPad2011

    2 de marzo de 2011 a las 2:16

  • Bien, probé esto y, para mi horror, finalmente descubrí que mi “matriz” se llenó con bits aleatorios. Supongo que los “datos” subyacentes se publicaron automáticamente antes de que terminara con la matriz. Poner una “retención” en los datos solucionó ese problema, pero ahora tengo que mantener una referencia al objeto “datos”, lo que hace que esta solución sea menos atractiva.

    – Desarrollador iPad2011

    2 de marzo de 2011 a las 4:24

  • @iPadDeveloper2011 Debe volver a leer la Guía de programación de administración de memoria en desarrollador.apple.com/library/ios/#documentation/Cocoa/Conceptual/…

    – Nikolái Ruhe

    2 de marzo de 2011 a las 9:06

  • @iPadDeveloper2011: debe repasar la gestión de la memoria. En este caso particular, los datos se están liberando automáticamente. Siempre que no se vacíe el grupo de liberación automática, este código está bien, pero una vez que llegue a un ámbito en el que podría haber un grupo de liberación automática que podría drenarse, ya no podrá usar los datos. Si necesita que dure más, entonces debe retain eso, y luego release cuando termines.

    – Adam Rosenfield

    2 de marzo de 2011 a las 15:49

  • Por mi parte, me encanta esta respuesta. Siempre me ha molestado cuando necesito usar matrices de enteros y perder el conteo de referencias, y poder extenderlos fácilmente. Gracias por la muy buena explicación y ejemplos!

    – Acatyyc

    21 de febrero de 2012 a las 20:56


Está perfectamente bien: Objective-C es un superconjunto estricto de C, por lo que si desea escribir C simple, no hay nada que le impida hacerlo. En muchos casos, es ventajoso usar malloc y free para evitar la sobrecarga del tiempo de ejecución de Objective-C.

Por ejemplo, si necesita asignar dinámicamente una matriz de un número desconocido de enteros, a menudo es más simple y fácil:

int *array = malloc(N * sizeof(int));  // check for NULL return value!
// use array[0]..array[N-1]
...
free(array);

Versus:

NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:N];
// use NSMutableArray methods to do stuff with array; must use NSNumbers instead
// of plain ints, which adds more overhead
...
[array release];

Estaba trabajando en un juego de palabras para iPhone y teníamos que cargar un diccionario de palabras válidas de varios megabytes. La lista de palabras se cargó en un gigante char matriz asignada con malloc(), con algunas optimizaciones inteligentes para reducir aún más el tamaño de la memoria. Obviamente, para algo como esto, la sobrecarga de usar un NSArray es completamente impráctico en el iPhone limitado. No sé exactamente cuál es la sobrecarga, pero ciertamente es más de un byte por carácter.

  • RE: ‘superconjunto estricto’. Aunque personalmente estoy (totalmente) de acuerdo con usted, ya que estamos discutiendo el desarrollo de Apple/iPhone, esta afirmación no es técnicamente cierta. Apple lo define así: Objective-C syntax is a superset of GNU C/C++ syntax. Superconjunto estricto tiene un significado muy específico, siendo el uso no calificado de superconjunto el menor de los dos (piense en “se comporta como” frente a “exactamente como”). El calificador de syntax lo restringe aún más hasta el punto en que es casi inútil, limitando efectivamente la obligación de Apple al Anexo A de la especificación C99: apenas 16 páginas de 552 en el estándar.

    – Juan

    20 de julio de 2009 a las 5:49

  • He tenido varios problemas al usar malloc/free en Objective C. Vea mi comentario sobre la respuesta de Nikolai. Aparte de eso, he tenido problemas con la asignación (copia) de punteros a matrices mallocadas para compartir la matriz mallocada entre objetos.

    – Desarrollador iPad2011

    2 de marzo de 2011 a las 2:25

  • Si bien es cierto que puede usar malloc() y free(), puede evitar la mayor parte de la sobrecarga del tiempo de ejecución usando en su lugar un NSMutableData de la longitud adecuada.

    –Steven Fisher

    2 de mayo de 2014 a las 2:34

Por supuesto tú lata use estas funciones, porque Objective-C es simplemente un superconjunto de C. Sin embargo, es poco común hacer este tipo de cosas, ya que Objective-C contiene objetos y formas de hacerlo más fácil.

Después de todo, podría escribir el código anterior como:

NSMutableArray *array = [[NSMutableArray alloc] init];

//Use the array, adding objects when need be

[array release];

Aunque tendrías que crear NSNumber objetos para almacenar ints (desde NSArray no permite agregar tipos que no sean objetos), generalmente es más común usar objetos, porque es más fácil mover datos, y las clases de matriz se integran más comúnmente con otras clases de Cocoa, y la administración de memoria generalmente es más sencillo que la gestión de memoria C estándar.

Además, si comienza a agregar o eliminar objetos de la matriz, los objetos de la matriz Cocoa hacen que esto sea mucho más fácil de hacer.

  • Esto parece una exageración si necesita una matriz simple de enteros. Especialmente la necesidad de crear objetos NSNumber me parece tan ineficiente. ¿Qué pasa si quiero asignar una matriz de 100 000 valores booleanos?

    – Philippe Leybaert

    19 de julio de 2009 a las 19:35

  • Tal vez, puede haber una ligera sobrecarga en comparación con el uso de matrices simples de números enteros. Pero ciertamente se usan más comúnmente que usar la administración de memoria C. Y si está asignando una matriz de 100,000 booleanos, entonces puede haber una mejor manera de hacerlo que la forma en que lo está implementando actualmente (a menos que sea un escenario hipotético).

    – Alex Rozanski

    19 de julio de 2009 a las 19:41

  • Esto es especialmente excesivo si se trata de objetos realmente simples. Por ejemplo, si fuera a construir MineSweeper para el iPhone, es órdenes de magnitud más rápido hacer que un cuadrado sea una estructura y malloc una matriz de estructuras que crear los cuadrados como objetos y ponerlos en un NSArray. Además, usará bastante menos memoria.

    – Dave DeLong

    19 de julio de 2009 a las 19:41

  • Por supuesto, depende del contexto de la pregunta, pero el uso de la gestión de memoria C estándar es bastante poco común. Además, como dije, pueden volverse más útiles si está manipulando los elementos de la matriz.

    – Alex Rozanski

    19 de julio de 2009 a las 19:44

  • Solo quiero señalar que una matriz de 100,000 booleanos (¿BOOL?) Ya es una solución ineficiente de memoria, porque cada BOOL es 1 byte, pero realmente solo necesita 1 bit. Entonces, aproximadamente 8 veces mejor usar una matriz de 100,000/8 caracteres y operadores bit a bit.

    – Desarrollador iPad2011

    2 de marzo de 2011 a las 2:59

Si se trata de tipos de C estándar, no es menos común o “OK” que en C. Así es como se hace en C, que es parte de Objective-C.

Tampoco es inusual escribir algún tipo de contenedor de objetos alrededor de estas cosas para armonizarlo con el resto de Cocoa (KVO, administración de memoria, etc.). Así que podrías crear una clase IntArray que haga el mallocing detrás de escena para que pueda retenerlo y liberarlo según sea necesario. Tenga en cuenta que esto no es estrictamente necesario; puede ser útil si ese tipo de estructura es una parte importante de su programa.

Está perfectamente bien usar malloc y puedes hacer tu propia administración de memoria. En realidad NSObject allocWithZone: usa malloc para obtener la memoria.

  • Es técnicamente calloc, pero sí. =)

    – Dave DeLong

    19 de julio de 2009 a las 19:43

  • En realidad, es técnicamente NSAllocateObject(). Lo que sucede a continuación es más complicado. Bajo ObjC2 con GC habilitado, NSAllocateObject() llamadas objc_allocate_object(). Bajo ObjC2 sin GC, u ObjC < 2, NSAllocateObject() llamadas class_createInstanceFromZone()que a su vez llama malloc_zone_calloc()que, como su nombre lo indica, es lógicamente equivalente a calloc(). A calloc() con un count de 1 es por definición indigistqushable de una asignación obtenida por malloc de la misma size que ha tenido su space is initialized to all bits zero (C99 7.20.3.1.2).

    – Juan

    20 de julio de 2009 a las 5:17

  • Es técnicamente calloc, pero sí. =)

    – Dave DeLong

    19 de julio de 2009 a las 19:43

  • En realidad, es técnicamente NSAllocateObject(). Lo que sucede a continuación es más complicado. Bajo ObjC2 con GC habilitado, NSAllocateObject() llamadas objc_allocate_object(). Bajo ObjC2 sin GC, u ObjC < 2, NSAllocateObject() llamadas class_createInstanceFromZone()que a su vez llama malloc_zone_calloc()que, como su nombre lo indica, es lógicamente equivalente a calloc(). A calloc() con un count de 1 es por definición indigistqushable de una asignación obtenida por malloc de la misma size que ha tenido su space is initialized to all bits zero (C99 7.20.3.1.2).

    – Juan

    20 de julio de 2009 a las 5:17

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad