Gestion de la mémoire

La première question que se posent la plupart des développeurs Java est de savoir comment la gestion de la mémoire est mise en œuvre par J2ObjC, étant donné que Java dispose de la récupération de mémoire, contrairement à Goal-C par défaut. iOS propose deux méthodes de gestion de la mémoire : le comptage de références et le comptage automatique de référence (ARC).

J2ObjC génère un code de gestion de mémoire différent selon la méthode choisie. Effectuez la traduction avec l'option -use-arc pour générer du code utilisant ARC. Par défaut, elle utilise le comptage manuel de référence.

Comptage des références

La méthode de comptabilisation des références rend explicite la propriété des objets. Une méthode est propriétaire d'un objet lorsqu'elle le crée, jusqu'à ce qu'elle le libère. Lors de la réception d'un objet d'une autre méthode, la méthode de réception le conserve s'il doit être référencé après le retour de la méthode. Lorsqu'une méthode n'a plus besoin de référencer un objet, elle doit le libérer. Lorsque le nombre de conservations d'un objet est égal à zéro, sa mémoire est libérée et l'objet n'est plus valide. Lorsque des objets sont libérés, leur méthode Dealloc() est appelée pour libérer la propriété de leurs variables d'instance.

L'un des problèmes avec cette technique est de transférer la propriété d'un objet. Par exemple, une méthode de fabrique peut être appelée pour créer un objet. Si la méthode de fabrique libère l'objet avant de le renvoyer (puisqu'il ne souhaite plus en être le propriétaire), cet objet est libéré avant que la méthode d'appel puisse le conserver.

Pour transférer la propriété d'un objet, une méthode lui envoie un message de libération automatique (au lieu d'un message de libération), qui diffère le message de publication. Cela permet à la méthode de fabrique de créer un objet à renvoyer et de renoncer à sa propriété sans invalider l'objet. À intervalles réguliers (par exemple, après chaque itération de boucle d'événements dans une application iOS), le pool de libération automatique est "drainé", ce qui signifie que tous les objets de ce pool reçoivent les messages de version différée. Tous les objets dont le nombre de conservations tombe à zéro sont libérés normalement.

Étant donné que la gestion de la mémoire incombe au développeur, il est facile de provoquer une fuite de mémoire avec la méthode de comptabilisation des références. Cependant, Apple recommande quelques bonnes pratiques mises en œuvre par J2ObjC pour minimiser ce problème.

L'environnement d'exécution et les outils sont également pris en charge pour détecter les fuites de mémoire. L'environnement d'exécution Objective-C signale toutes les fuites détectées lorsqu'une application se ferme. C'est l'une des raisons pour lesquelles J2ObjC convertit les tests JUnit en binaires exécutables. Xcode utilise Clang. Ce compilateur offre une excellente analyse statique des problèmes de mémoire, que Xcode met à disposition avec sa commande "Analyze" (Analyser).

Décompte automatique de référence (ARC)

ARC est la méthode de gestion de mémoire recommandée par Apple. Elle transfère la responsabilité du décompte des références au compilateur, qui ajoute les méthodes de conservation, de publication et de libération automatique appropriées lors de la compilation. ARC est compatible avec les références faibles pour les appareils exécutant iOS 5 et versions ultérieures.

Nous recommandons que les projets utilisent ARC pour traduire le code. Le code Objectif-C transpilé est comme du code Objectif-C manuscrit. L'utilisation d'ARC peut aider les développeurs à éviter les erreurs courantes liées à la mémoire, telles que la sur-publication ou le sous-référencement, ce qui simplifie la gestion de la mémoire et réduit le risque d'erreur.

Notez que ARC n'est pas adapté aux exceptions par défaut. Plus précisément, elle fuite de la mémoire lorsque des exceptions sont générées. Étant donné que les exceptions sont plus courantes en Java et sont généralement récupérables, cela peut s'avérer problématique. L'utilisation de -fobjc-arc-exceptions lors de la compilation avec un arc permet de corriger les fuites avec un coût de performances acceptable.

Nous recommandons également aux nouveaux projets d'utiliser ARC pour leur code Objectif-C écrit à la main, et de ne recourir au comptage manuel de référence que si les données de profilage présentent un problème de performances réel. Le code ARC et le code non-ARC peuvent être compilés et associés dans la même application sans problème.

Références faibles

Les champs peuvent être annotés avec com.google.devtools.j2objc.Weak, que le transpilateur utilise pour générer des champs qui suivent la sémantique de référence de faible valeur Objectif-C. Lorsque vous utilisez la comptabilisation de références, cela signifie que le champ n'est pas conservé lors de l'initialisation et qu'il est libéré automatiquement lorsque l'instance conteneurisée est libérée. Avec ARC, les champs faibles sont marqués avec l'annotation __unsafe_unretained, et les propriétés associées sont déclarées comme faibles.

Dans certains cas, une instance de classe interne se trouve dans un cycle de référence avec son instance externe. Ici, une annotation com.google.devtools.j2objc.WeakOuter est utilisée pour marquer la classe interne. La référence à la classe externe est donc traitée comme décrit ci-dessus. Les autres champs de la classe interne ne sont pas affectés par cette annotation.

J2ObjC prend également en charge la classe WeakReference. Le code Java qui l'utilise fonctionnera donc de la même manière une fois traduit. Notez que WeakReference est intrinsèquement non déterministe sur la JVM. Les applications qui souhaitent éviter les fuites de mémoire tout en maintenant la prévisibilité doivent privilégier @Weak et @WeakOuter.

Outils de gestion de la mémoire

  • Cycle Finder Tool : analyse les fichiers sources Java pour identifier les cycles de référence d'objets importants.
  • Xcode Instruments : suite d'outils de profilage de Xcode.
  • Xcode Memory Diagnostics : options de compilation pour l'exécution avec diagnostics et journalisation de la mémoire