Administración de memoria

La primera pregunta que se hacen la mayoría de los desarrolladores de Java es cómo J2ObjC implementa la administración de memoria, ya que Java tiene recolección de elementos no utilizados, y Objective-C no la implementa de forma predeterminada. iOS tiene dos métodos de administración de memoria: el recuento de referencias y el recuento automático de referencias (ARC).

J2ObjC genera un código de administración de memoria diferente, según el método que se elija. Traduce con la opción -use-arc para generar un código que use ARC. De forma predeterminada, usa el recuento de referencias manual.

Recuento de referencias

El método de recuento de referencias hace que la propiedad de los objetos sea explícita. Un método es propietario de un objeto cuando lo crea, hasta que lo libera. Cuando se recibe un objeto de otro método, el método receptor retiene el objeto si es necesario hacer referencia a él después de que se muestra el método. Cuando un método ya no necesita hacer referencia a un objeto, debe liberarlo. Cuando el recuento de retenciones de un objeto es cero, su memoria se libera y el objeto ya no es válido. Cuando se liberan objetos, se llama a su método "saleloc()" para liberar la propiedad de sus variables de instancia.

Un problema con esta técnica es cómo transferir la propiedad de un objeto. Por ejemplo, se puede llamar a un método de fábrica para crear un objeto. Si el método de fábrica libera el objeto antes de mostrarlo (debido a que ya no quiere poseer el objeto), ese objeto se libera antes de que el método de llamada pueda retenerlo.

Para transferir la propiedad de un objeto, un método le envía un mensaje de lanzamiento automático (en lugar de un mensaje de actualización), que aplaza el mensaje de actualización. Esto permite que el método de fábrica cree un objeto que se mostrará y renuncie a su propiedad sin invalidar el objeto. A intervalos regulares (por ejemplo, después de cada iteración de bucle de eventos en una aplicación para iOS), el grupo de versiones automáticas se “desvía”, lo que significa que todos los objetos de ese grupo reciben los mensajes de actualización diferidos. Cualquier objeto cuyo recuento de retenciones se reduzca a cero se libera con normalidad.

Debido a que la administración de la memoria recae sobre el desarrollador, es fácil perder memoria con el método de recuento de referencia. Sin embargo, Apple recomienda algunas prácticas recomendadas para minimizar este problema, que J2ObjC implementa.

También es compatible con el entorno de ejecución y con herramientas para detectar fugas de memoria. El entorno de ejecución de Objective-C informa cualquier fuga detectada cuando se cierra una aplicación, que es uno de los motivos por los que J2ObjC traduce las pruebas JUnit en objetos binarios ejecutables. Xcode usa Clang, y ese compilador ofrece un excelente análisis estático para los problemas de memoria, que Xcode pone a disposición con su comando Analyze.

Recuento automático de referencias (ARC)

ARC es el método de administración de memoria recomendado de Apple. Traslada la responsabilidad del recuento de referencias al compilador, lo que agrega los métodos adecuados de retención, lanzamiento y lanzamiento automático durante la compilación. ARC admite referencias débiles para dispositivos que ejecutan iOS 5 y versiones posteriores.

Recomendamos que los proyectos usen ARC para traducir el código. Transpilado El código Objective-C es igual al código Objective-C escrito a mano. El uso de ARC podría ayudar a los desarrolladores a evitar errores comunes relacionados con la memoria, como un lanzamiento excesivo o una referencia insuficiente, lo que hace que la administración de la memoria sea más sencilla y sea menos propensa a errores.

Ten en cuenta que ARC no tiene seguridad de excepciones de forma predeterminada. Específicamente, pierde memoria cuando se producen excepciones. Dado que las excepciones son más comunes en Java y, por lo general, se pueden recuperar, esto puede ser un problema. El uso de -fobjc-arc-exceptions cuando compilas con arco corregirá las fugas con un costo de rendimiento aceptable.

También recomendamos que los proyectos nuevos usen ARC para su código Objective-C escrito a mano y solo recurran al recuento de referencias manual si los datos de generación de perfiles muestran un problema de rendimiento real. Tanto el código ARC como el que no es de ARC se pueden compilar y vincular en la misma app sin problemas.

Referencias débiles

Los campos se pueden anotar con com.google.devtools.j2objc.Weak, que el transpilador usa para generar campos que siguen la semántica de referencia débil de Objective-C. Cuando se usa el recuento de referencias, esto significa que el campo no se retiene cuando se inicializa y se libera automáticamente cuando se libera la instancia que lo contiene. Con ARC, los campos débiles se marcan con la anotación __unsafe_unretained y las propiedades relacionadas se declaran como débiles.

En algunos casos, una instancia de clase interna entra en un ciclo de referencia con su instancia externa. Aquí, se usa una anotación com.google.devtools.j2objc.WeakOuter para marcar la clase interna, de modo que la referencia a la clase externa se trata como se describió anteriormente. Otros campos de la clase interna no se ven afectados por esta anotación.

J2ObjC también admite la clase WeakReference, por lo que el código Java que la use funcionará de la misma manera cuando se traduzca. Ten en cuenta que WeakReference es inherentemente no determinista en la JVM; las aplicaciones que deseen evitar fugas de memoria y, al mismo tiempo, mantener la previsibilidad deberían preferir @Weak y @WeakOuter.

Herramientas de administración de la memoria