ARC et Structures C, problème de fuite de mémoire avec malloc...
Bonjour,
D'après la doc, cela a l'air "normal" : il semble qu'il soit déconseillé d'utiliser des structures C sous iOS avec ARC.
Jusqu'à présent, sous MacOS, je n'utilisais pas ARC. Les structures avaient un comportement très stable. Avec ARC, elles "fuient" à peine initialisées.
Je fais la méthode
monInstance = malloc(sizeof(maStructureC));
dans la méthode init. Pas de problème tant que j'utilise cette structure dans "init". Mais dès que j'appelle cette structure dans une autre méthode, elle a disparu...
J'ai implémenté les "free(monInstance)", méthode appelée depuis l'AppManager à la fermeture, j'ai essayé de mettre "_strong" au moment des "typedef", etc.
J'ai lu ceci :
ou cela :
Je crains devoir me passer de ces structures pourtant bien commodes (et devoir beaucoup réécrire mon code venant de MacOS au passage...), mais peut-être que quelqu'un "a un truc"??
Merci par avance dans ce cas!
Réponses
Si je ne m'abuse les types opaques de CoreGraphics (CG*) sont bien des structures non ?
Ils font comment eux ?
C'est vrai que le mieux c'est quand même d'avoir des objets.
D'autant que maintenant, avec le property-auto-synthesis + ARC et tout le reste, ça a apporté beaucoup, et que maintenant une sous-classe de NSObject peut juste s'écrire : Donc c'est aussi compact que de déclarer une structure Person équivalente.
Oui, j'ai compris que pourtant (si j'ose dire), les objets pouvaient être utilisés comme des structures, du genre :
@property(assign) float valeursOnde[24];
J'en ai pourtant besoin..
Sans parler du fait que j'emploie des structures imbriquées, avec des tableaux de la structure A dans la structure B...
Le problème vient peut-être d'ailleurs, car j'utilise aussi des structures C dans les classes graphiques, et là leur comportment est stable.
C'est avec la classe audio que j'ai ce problème...
Aucun problème par rapport à cela, c'est ce que j'ai toujours fait. Mais "malloc" ne semble pas suffire... J'ai essayé aussi "calloc", pas mieux.
C'est étonnant parce que tout CoreAudio fonctionne avec des structures C!! Bon, on voit demain...
Alors, soyons clair: ARC gère la mémoire des objets Cocoa; c'est à dire que tu n'as plus à te palucher toi-même les retain, release et autorelease. Mais c'est tout. ARC ne gère pas la mémoire des structures ni des objets Core Foundation.
Maintenant, s'il est déconseillé d'utiliser des structures, c'est parce qu'elles deviennent du coup moins pratiques que des classes, puisque justement tu vas devoir gérer leur allocation et leur libération à la main. Ceci dit, les structures restent un outil judicieux quand les performances sont en jeu. Crois-moi, CGRect n'est pas prêt de disparaà®tre !
Je le répète, ARC ne gère pas la mémoire des structures, mais la mémoire des objets Cocoa. Si ton objet est codé comme ça:
Alors c'est parfait. La structure sera conservée en mémoire tant que l'objet sera conservé en mémoire. Maintenant, si tu t'amuses à passer la structure à un autre objet et que l'objet est libéré, alors forcément, la structure sera également libérée et tu auras un plantage.
Merci Céroce, cela me rassure. Je ne vois pas où j'ai pu libérer la mémoire, d'autant plus que c'est dès la méthode d'initialisation que le problème se pose.
Est-ce que le fait que la classe concernée soit une classe partagée ("shareInstance") que le problème se pose? Sans-doute dois-je utiliser la méthode "+ (instancetype) sharedManager" pour la méthode init?
Alors va pour une partie du code, le reste est pareil :
Les structures :
le "+instanceType" :
L'init : (- (id) init{})
En haut de ton fichier .m ?
Merci Céroce. Que veux-tu dire exactement?
En dessous de "@implementation AudioManager", cela ne donne rien de mieux, et bien sûr on ne peut le mettre dans le header. Sinon il est dans la méthode "+ (instancetype) sharedManager.(voir plus haut)
Ceci dit, le AUGraph audio lui aussi a tendance à "fuiter", donc le problème semble bien venir de l'instanciation de la classe AudioManager
Avec les @property pour les types premiers.
Bon y'a peut-être une raison pour laquelle tu préfères un pointeur de struct que la struct direct, et ça explique pas le problème que tu as si tu nous dis que ton *mesParametresSon est NULL après le init, mais bon.
Bonne remarque AliGator. Bien souvent, dans les structures imbriquées, j'emploie des tableaux de structures (comme "MesParametresNotes mesNotes[12];" dans "struct MesParametresSon". En fait, je me sers des structures comme de classes sans méthode!
Je trouvais l'écriture plus simple que l'appel de tableaux en Objectiv-C :
au lieu de
Ceci dit, le problème n'est apparemment pas là . C'est triste car c'est le moteur audio!
Sinon je fais "à l'ancienne", je l'instancie dans un UIViewController ou l'AppDelegate et je le passe aux autres classes graphiques. Mais comment fait-on alors? Pas moyen de faire des UIViewController les IBOutlet les uns des autres, et AppManager n'apparaà®t pas pas dans les story board d'IB?
Remarque :
Dans le AppDelegate, et bien que j'appelle à chaque fois dans le code [AudioManager sharedManager], je dois bien faire :
??
permet d'appeler des instances de l'AppDelegate depuis les UIViewController. J'ai essayé, mais la fuite de mémoire demeure, dans le AU graph au moins. (la communication semblait passer depuis les interfaces graphiques testées vers l'audio manager; j'ai copié via des "@property" l'instance de l'AppDelegate vers les classes du GUI).
Je vous embête encore avec mon problème :
J'ai toujours cette erreur :
tout en ayant changé la création de l'audioManager (désormais créé avec un classique alloc-init et passé de classes en classes avec [[UIApplication sharedApplication] delegate]; ).
En fait, à la première utilisation la classe est stable parfois (j'ai vérifié avec des NSLog, il s'agit bien de la même instance), tandis que lorsque je relance un nouveau test, alors cela plante. Il me faut redémarrer le Mac pour que cela cesse de planter... au mieux une seule fois!
Surtout, j'ai mis un message console (NSLog) sur la méthode "dealloc" de la classe, je ne le vois jamais apparaà®tre en console. Aussi le problème vient sans doute de là (j'ai tendance à arrêter la simulation avec le bouton "stop" de XCode plutôt que depuis le simulateur.)
(Cela faisait la même chose avec "shareInstance", mais il semble que le comportement de la classe concernée soit tout de même plus stable maintenant.)
Quelqu'un aurait une idée? Un synthé avec une classe audio qui plante, je ne le sens pas...
Merci par avance.
Merci Céroce. J'ai commencé à supprimer une des structures en en faisant une classe. Ce qui est étonnant est que l'autre structure fonctionne parfaitement!
Je me demande si le problème ne venait pas des tableaux de flottants imbriqués dans ces structures (les bugs semblaient venir de là )
L'initialisation de "desNombres" posait problème.
A moins que cela ne vienne du fait que j'avais plusieurs jeux de structures imbriquées? Mais je ne pense pas. C'est bien mes tableaux dans mes tableaux dans... qui buggaient. (les structures restantes sont aussi imbriqués les unes dans les autres, mais sans tableaux de types premiers)
Les premiers tests avec la nouvelle classe sont bons, il n'y a plus qu'à réécrire beaucoup du code pour MacOS...
Cela remarche. J'ai donc fait des classes pour supprimer les structures contenant les tableaux de float.
C'est "résolu", mais je suis surpris que la structure initiale n'ait pas marché... (que ce soit avec une "shared instance", ou avec une instance copiée de classe à classe).
Ce sont ces deux lignes qui faisaient apparemment que la structure était désallouée en mémoire. Dans le contrôle de l'utilisation de la mémoire de XCode, on voyait un pic soudain lors du lancement qui disparaissait tout aussi soudainement.
Du moins c'est ce qui me paraà®t le plus plausible.