didReceiveMemoryWarning non appelé

Salut à  tous,



L'application que je développe crash sur l'iphone(3GS) du client (c'est pas marrant quand ça marche), alors que sur mon iPhone(4) tout marche bien.

J'ai réussi à  me procuré un iPhone 3GS pour pouvoir debbugé plus facilement. Et je remarque que l'application utilise continuellement de la mémoire sur l'iPhone 3GS et dès que y'a plus de mémoire l'application crash.

Bizarrement je n'ai aucunes leaks et je ne sais pas pourquoi l'application consomme autant de mémoire sur l'iphone (si seulement j'arrivé a lancé instruments sur l'iphone, mais instruments plante des qu'il est lancé).

Mais le plus bizzare c'est que je ne reçois pas de memory warning et donc la méthode didReceiveMemoryWarning de mes viewControllers n'est jamais appelée.



Je ne sais pas où chercher. Quelqu'un pour m'aider ?



Merci beaucoup.

Réponses

  • Tu peux simuler un Memory Warning à  partir du simulateur, dans la barre d'outils :

    Matériel->Simuler un avertissement de mémoire



    J'ai déjà  eu un problème semblable au tiens, peux tu en dire davantage sur la transition entre tes vues (je pense que ça peux principalement venir de la).
  • Ah oui j'ai oublié de préciser: Dans le simulateur, le Memory Warning enclenche bien la méthode didReceiveMemoryWarning de mon controller.



    Ah vrai dire je peux réussir a faire planter l'application seulement sur le premier ViewController. Donc sans aucune transition entre les vue.

    Je peux admettre que mon ViewController consomme beaucoup de memoire, c'est une tableview dont chaque cellule est une grosse image. J'utilise un NSCache pour mettre en cache les images. Alors la memoire peut monter assez facilement (quoi que je limite mon NSCache a seulement 5 elements donc 5 images). Mais je comptais sur le didReceiveMemoryWarning pour vider mon NSCache.



    Sachant que je n'es pas de leak, je trouve bizarre aussi quand je désalloue mon ViewController, le taux d'occupation mémoire ne retombe pas.
  • FKDEVFKDEV Membre
    Peux-tu préciser avec quelle version d'iOS tu travailes sur les deux iPhone ?



    Beaucoup de développeurs se sont plaint de la gestion mémoire des UIImage.

    Je ne peux pas en dire plus car je n'ai jamais eu de problèmes mais regarde ce post par exemple :

    http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/
  • C'est la version 5.0 sur les deux iPhones.

    J'ai remarqué ce matin, que mon iPhone4 aussi consomme beaucoup de memoire, mais il en libère aussi beaucoup. Chose que l'iphone 3GS ne fait pas.



    Au depart j'utilisais [UIImage imageNamed:] mais j'ai vite compris que les images une fois allouées par imageNamed, n'étaient jamais libérées (sa leak dans instruments). Donc pour le moment j'utilise une méthode un peu similaire à  ce qui est précisé dans le lien que tu m'as donné.
  • FKDEVFKDEV Membre
    mai 2012 modifié #6
    Si tu ne peux pas utiliser Instruments sur le 3GS ça va être difficile de comprendre ce qui se passe.

    As-tu essayer l'outil "Allocations" pas leaks sur l'iPhone 4 pour voir le profil de la courbe des objets alloués.

    Tu pourras peut-être extrapoler et comprendre ce qui se passe.



    Question idiote : as-tu essayé de réduire le nombre d'objets max acceptable dans NSCache.



    Là  je lance des hypothèses au hasard :

    -l'iPhone 3GS possède 2 fois moins de RAM que l'iPhone 4 donc il est peut-être "étouffé" avant d'avoir eu le temps de commencer à  libérer.

    -l'iPhone 3GS est moins rapide, il n'a peut-être pas le temps de vider les NSCache (je ne sais pas par quel processus NSCache décide de libérer ses objets).




    Sachant que je n'es pas de leak, je trouve bizarre aussi quand je désalloue mon ViewController, le taux d'occupation mémoire ne retombe pas.


    Ton NSCache est bien libéré en même temps que le controller ?
  • jojolebgjojolebg Membre
    mai 2012 modifié #7
    Question idiote : as-tu essayé de réduire le nombre d'objets max acceptable dans NSCache.


    Oui pour le moment il est a 5, mais meme quand il est a 1 cela se produit.







    [font=helvetica, arial, sans-serif]
    Ton NSCache est bien libéré en même temps que le controller ?


    Normalement c'est ARC qui s'occupe de liberé ce NSCache, et vu que je l'utilise seulement dans ce controller, il doit être automatiquement libéré quand son possesseur est libéré nan ?[/font]






    [font=helvetica, arial, sans-serif]Là  je lance des hypothèses au hasard :[/font]

    [font=helvetica, arial, sans-serif]-l'iPhone 3GS possède 2 fois moins de RAM que l'iPhone 4 donc il est peut-être "étouffé" avant d'avoir eu le temps de commencer à  libérer[/font][font=helvetica, arial, sans-serif].[/font]




    Pour le moment je pense que c'est ça qui est le plus probable.



    Apres une analyse un peu plus poussé de mon code (je vérifierai se soir, je pense que le NSCache n'est pas directement en cause.

    En effet dans le cellForRowAtIndexPath de mon controller, j'appelle une méthode qui s'occupe de charger l'image, de la mettre en cache puis de l'afficher.

    Dans cette méthode la (je donnerais du code dimanche si je ne m'en sors toujours pas d'ici la) je lance le chargement de l'image dans un thread separé (avec GCD). Puis à  la fin du chargement je lance dans le main thread (toujours avec GCD) l'affichage de l'image dans la cellule seulement si nécessaire (si l'indexPath n'a pas changé entre temps).

    J'ai remarquer quand je slide assez vite ma tableview, toutes les cellForRowAtIndexPath sont appellées entre le point de depart et le point d'arrivé, et par la meme occasion elles vont me crées autant de thread necessaire pour charger les images (dans la limite des threads disponibles).

    Je pense que le soucis vient de la, en effet si je scroll ma tableview assez vite, l'iphone chargera peut être toutes les images des cellules, et meme si ils ne les met pas en toutes en cache (parceque le cache est limité) il les gardes en memoire (jusqu`à  quand ? la fin du thread surement). C'est ce pique de memoire qui fait planter l'iphone 3GS. L'iphone 4 possédant plus de memoire ne plante pas, puis des que tout les thread sont fini, j'ai l'impression que la memoire revient, et l'iphone 4 peut s'en sortir plus aisement.



    Je reviendrai dès que je trouve un sollution (ou pas) pour dire si mon analyse est bonne.



    Merci encore.
  • FKDEVFKDEV Membre
    Clairement cela vient de là .

    Il faudrait que tu vois si tu ne peux pas arrêter les threads qui sont associés à  une cellule qui va être réutilisée (de mémoire il y a une méthode prepareToReuse sur la cellule) parce que là  cela ne sert plus à  rien de charger l'image.
  • De memoire, sais-tu comment on arrete un thread en cours d'éxécution avec GCD ?

    Je pense que je vais m'orienté vers les NSOperationQueue et les NSOperation pour géré çà  plus facilement.
  • zoczoc Membre
    'jojolebg' a écrit:


    Je pense que le soucis vient de la, en effet si je scroll ma tableview assez vite, l'iphone chargera peut être toutes les images des cellules


    Il suffit tout simplement de ne pas lancer le téléchargement des images tant que la vue scrolle... Ca évite de charger des images qui, quoi qu'il arrive, ne seront pas affichées.



    Voir l'exemple "LazyTableImages" d'Apple. C'est un point de départ parfait pour ce genre de chose. Parce que quoi qu'il arrive, même avec un iPhone 4 ou ultérieur, charger toutes les images, ça finira obligatoirement un jour par faire planter n'importe quel device... Ce n'est qu'une question de nombre de lignes dans la table.
  • FKDEVFKDEV Membre
    Je ne sais pas comment on "arrête" un thread mais il faudrait de toutes façons le faire proprement, avec un flag cancel. Reste à  voir si tu peux annuler un chargement d'image en cours (c'est pas du download je crois).



    Je n'avais jamais regardé lazytableimages, c'est sans doute mieux d'attendre l'arrêt du scroll pour telecharger, plutot que de lancer les telechargements dans cellForRow...

    Mais ça ne règle pas le problème de mémoire. Dans l'exemple, c'est l'avertissement mémoire qui provoque l'annulation des téléchargements. Ici il n'y a pas d'avertissement mémoire, ce qui veut dire que la main loop n'a pas le temps de les traiter.



    Si tu ne veux pas trop changer ton code, tu pourrais faire l'essai de forcer un délai entre chaque démarrage de thread, ce qui permettrait de vérifier si le memory warning est reçu. En utilisant simplement performSelector:afterDelay:.



  • Je procède maintenant au chargement des images dans la méthode scrollViewDidEndDecelerating: et scrollViewDidEndDragging:WillDecelerating: comme sur l'exemple de LaryTableImage et tout marche niquel.



    Merci
Connectez-vous ou Inscrivez-vous pour répondre.