Gestion des crashes à  cause de la pression sur la mémoire

colas_colas_ Membre
août 2015 modifié dans API UIKit #1

Bonjour à  tous,


 


Je voudrais m'attaquer à  la partie "mémoire sous pression" de mon app.


 


Jusqu'à  maintenant mon app tient le coup, avec une utilisation mémoire qui tourne autour de 75Mb.


 


Mais, lorsqu'elle passe à  l'arrière plan et que je lance safari pour faire une recherche par exemple, elle plante et un message s'affiche dans Xcode qui me dit que c'est à  cause de la mémoire.


 


Je voudrais comprendre ce qui se passe (et régler le problème), et avant de me lancer là -dedans, je voulais avoir vos lumières :


 


1/ j'imagine que tout se passe dans - (void)didReceiveMemoryWarning. Qu'est-ce que je dois y faire typiquement ? Je ne peux pas dealloc le VC... Que s'y passe-t-il ? Les VCs tombent-ils les uns après les autres ? Ou bien, tout tombe d'un coup et l'appli et relaunchée ? En l'occurrence, dans mon cas, quand je rouvre l'appli, je me retrouve sur l'écran d'accueil de mon app.


2/ j'ai pas mal de VCs, car j'ai pas mal d'écrans mais aussi car je les imbrique les uns dans les autres pour construire mes écrans : dois-je gérer la méthode dans tous les VCs ? Y a-t-il un pattern conseillé pour cette situation ? (genre un singleton dédié à  ce problème)

3/ quelles ressources à  lire/regarder me conseillez-vous ?

 

SI vous avez d'autres idées ou des questions, des piste...

 

Merci !

Réponses

  • CéroceCéroce Membre, Modérateur
    La méthode -didReceiveMemoryWarning est appelée lorsque le système commence à  manquer de mémoire.
    À ce moment, il faut te débarrasser de toutes les ressources que tu peux recréer, typiquement des images.

    Je ne pense pas qu'une approche systématique soit bonne. La question est de savoir où ça bouffe de grosses quantités de RAM pour pouvoir agir à  ces endroits précis.
  • Merci de ta réponse @Céroce.




    Je crois que pour l'instant, je n'ai pas trop envie de gérer ça (dealloc des images et refetch) : ça impliquerait que je change mon archi. Ce qui est possible en revanche, c'est que je dézingue les VCs qui prennent trop de place (et revenir aux écrans précédents).


     


    J'aimerais aussi comprendre ce qu'il se passe en fait quand la mémoire manque (dealloc? ou crash total et relance de l'app en tâche de fond)


  • Ce qui est également bizarre c'est que la mémoire sature une fois que tu as quitté l'application et non pendant, tu sais d'où ça vient ?


  • zoczoc Membre

    La mémoire sature parce qu'il lance une autre application (Safari) qui a besoin de mémoire. Donc soit il obtempère quand le système lui dit de faire de la place, soit son application est tuée.



  • Ce qui est également bizarre c'est que la mémoire sature une fois que tu as quitté l'application et non pendant, tu sais d'où ça vient ?




    On ne quitte jamais une application. Tu crois la quitter, mais iOS se contente de la placer en tâche de fond.



  • On ne quitte jamais une application. Tu crois la quitter, mais iOS se contente de la placer en tâche de fond.




     


    euh oui je voulais dire mettre en fond  ^_^


     


     




    La mémoire sature parce qu'il lance une autre application (Safari) qui a besoin de mémoire. Donc soit il obtempère quand le système lui dit de faire de la place, soit son application est tuée.




    ah ok ! Donc en fait iOS notifie les app en fond quand une active utilise trop de mémoire ?

  • On peut faut voir les choses ainsi :

    Idéalement quand tu lances une app, tu reviens où tu étais quand tu l'as quittée. Sachant que quitter peut signifier répondre à  un appel téléphonique ou autre interruption.


    Pour faire cela, le plus simple est de garder les apps en mémoire. En pratique la memoire etant limité, ona plusieurs degrzdation de ce principe, la premiere etant de demander à  l'app de liberer ce qui n'est pas indispensable au maintien de l'etat de l'app.

    Donc si tu as une app qui affiche une image correspondant à  un état, tu peux libérer l'image mzis conserver l'etat.

    Si la pression devient trop forte le systeme te previent qu'il va te tuer pour que tu puisses sauvegarder cet état pour y revenir au lancement. En pratique on sait bien que c'est tres difficile sur des apps complexes ou les VC ont ete empiles.


    Pour repondre a ta question suivant le principe ci-dessus, il ne faut surtout pas libérer les controller (qui vont contenir des états), mais plutot les vues. Idealement tu dois pouvoir liberer tout ce qui a ete alloué dans viewdidload, puis liberer la vue elle-même : self.view.

    Quand le controller sera reafficher, il recreeda toutes les vues en fonctikn de l'etat qu'il a consrrvé.
  • @fkdev


    Si je comprends bien, ce n'est pas didReceiveMemoryWarning que je dois faire le nettoyage mémoire mais avant (dans un méthode genre applicationWillGoBackground). En pratique, comment fais-tu pour libérer la vue ?


    Si je suis ton raisonnement, un autre problème risque d'être soulevé : quid de l'image qui sera affichée lorsque le système iOS présente toutes les apps ouvertes ?


    Au final, j'ai l'impression que ça va être compliqué...
  • DrakenDraken Membre
    août 2015 modifié #10


    Si je suis ton raisonnement, un autre problème risque d'être soulevé : quid de l'image qui sera affichée lorsque le système iOS présente toutes les apps ouvertes ?

     




    Quand iOS présente toutes les applications ouvertes, il affiche en fait des copies d'écran réalisées avant que l'application n'entre en tâche de fond. C'est automatique, tu n'as pas à  t'en occuper. 


     


    Si l'application a été détruite par iOS pour récupérer de la mémoire, il se contente d'afficher la copie d'écran, faisant croire à  l'utilisateur qu'elle est toujours là . Et peut la redémarrer discrétement si l'utilisateur veut s'en servir de nouveau.


  • FKDEVFKDEV Membre
    août 2015 modifié #11

    Non c'est bien dans didReceiveMemoryWarning, c'est-à -dire uniquement quand le système a besoin de mémoire, pas la peine d'anticiper les besoins du système.


     


     


    Un exemple de  cette fonction sur iOS 6 et + (attention c'est assez différent sur iOS < 6)



    - (void)didReceiveMemoryWarning
    {
    //libérer les vues qui peuvent recréer dans viewDidLoad
    if ([self isViewLoaded] && [self.view window] == nil) {
    self.view = nil;
    self.myToolbar = nil;
    self.mySubview = nil;
    }
    //libérer des données qui pourront etre recrées facilement
    self.queryResult = nil;

    [super didReceiveMemoryWarning];
    }

    Attention au fait que self.view va recréer la vue et provoquer l'appel de viewDidLoad si la vue a déjà  été libérée, c'est pour cette raison qu'on utilise self.isViewLoaded.


  • Je présume que ça doit se mettre dans chaque Contrôleur ? Et que iOS envoie le message didReceiveMemoryWarning à  tous les contrôleurs présents en mémoire ?

  • AliGatorAliGator Membre, Modérateur
    août 2015 modifié #13
  • @fkdev intéressant ce self.view = nil... J'aurais jamais suspecté que la vue soit recréée après.
  • J'ai observé que quand je passe mon app à  l'arrière plan, l'empreinte mémoire diminue drastiquement !


    Intéressant à  savoir !! Je pense que cette diminution de mémoire se fait en dehors des messages type didReceiveMemoryWarning


     


  • AliGatorAliGator Membre, Modérateur
    Il y a pas mal de classes Apple qui gèrent ça toutes seules, s'adonnant à  la notification de passage en background ou d'alerte mémoire et gérant le cas de leur côté.


    Par exemple c'est le cas de NSCache qui est justement fait pour ça


    ça ne m'étonnerai pas non plus que des classes comme UIImage et les images créés par imageNamed se libèrent automatiquement de la mémoire quand elles reçoivent la notification et rechargent l'image ensuite quand tu reviens (et que tu en as de nouveau besoin, sans s'embêter à  recharger les images qui ne sont plus a l'écran tant que tu ne les redemandes pas). Genre de chose qui serait tout à  fait logique car une bonne façon de faire pour être un bon citoyen vis à  vis de l'utilisation mémoire... et expliquerait parfaitement ton comportement que tu décris.
Connectez-vous ou Inscrivez-vous pour répondre.