Problème bizarre : CFRunLoopRunSpecific

Philippe49Philippe49 Membre
juin 2009 modifié dans Apple Developer Programs #1
Une appli qui marchait si bien depuis 6 mois ! puis Passage au nouveau simulator 3.0 et device 3.0 :
  • On fait agir plusieurs fois l'interface : CABasicAnimations, timers relativement nombreux, Changement de view controllers, ajout/suppressions de vues, changement de fond d'écran, etc..
  • On laisse reposer quelques minutes

et là  une méchanceté, la mouche dans le lait :
malloc_error_break : double free  sur 0x..


Je passe sur Instruments. le bug est difficile à  faire apparaà®tre ( 10-15 minutes), et j'ai une pile d'instructions qui finit par ... CFRunLoopRunInMode , CFRunLoopRunSpecific

Ben là , je sèche complètement. Cela ne se passait pas depuis 8 mois que l'appli existe au niveau des timers et animations. Les dernières modif ne semblent pas être la cause, car j'ai essayé avec la version N-1 .

A quoi peut référer ce CFRunLoopRunSpecific ?

Réponses

  • Philippe49Philippe49 Membre
    juin 2009 modifié #2
    J'ai réussi à  la reproduire ...
    En consultant la liste des threads alloués par mon application, le thread qui est cité dans le rapport d'Instruments, n'a pas été créé par mon appli

    Voici la pile d'exécution
  • AliGatorAliGator Membre, Modérateur
    10:12 modifié #3
    CFRunLoopSpecific est une méthode interne du framework permettant de faire s'exécuter une RunLoop... dans un mode spécifique (c'est à  dire en ne sélectionnant que certaines CFRunLoopSources qui ont le droit de "réveiller" la RunLoop).

    Je ne sais pas si tu sais comment fonctionnent les runloops, en Cocoa et en général. Il s'agit tout simplement de boucles qui attendent qu'un événement arrive pour se réveiller. C'est typiquement ce qui est utilisé pour le thread principal (qui est le seul thread pour lequel la runloop est créée, configurée et exécutée automatiquement, pour tes threads secondaires si tu veux une runloop il faut la configurer et lancer, un peu à  l'image des NSAutoreleasePools), pour "watcher les events" tels que les interactions utilisateurs par exemple.

    Une RunLoop peut avoir comme source des données arrivant sur un NSPort, des timers (c'est la runloop qui est en charge d'exécuter les actions associées au NSTimers aux bons moments, en vérifiant les fireDates à  chaque itération de la runlopp... c'est pas magique un NSTimer hein ;) faut bien que qqun s'en occupe :P), ou des invocations demandées par un autre thead et empilées pour exécution (tous les performSelector:onThread:withObject:waitUntilDone:, c'est la RunLoop qui dépile ces "demandes" d'invocations de méthodes et les exécute).

    D'ailleurs si tu crées un thread secondaire, et que tu demandes [tt]performSelector:... onThread:tonThreadSecondaire withObject:... waitUntilDone:...[/tt] alors que ton thread secondaire n'a pas de RunLoop, le selector ne sera jamais "performed"... tu peux toujours attendre. (J'ai d'ailleurs eu le problème récemment, et je me suis arraché les cheveux une journée entière dessus pour capter que ça venait de là )



    Maintenant, pour ton bug plus particulier, le pb quand ça plante dans une RunLoop, c'est que c'est vraiment difficile de savoir d'où ça vient... car justement c'est les CFRunLoops qui gèrent toutes les actions "en attente" ou "en arrière plan"... Donc ça peut avoir planté sur un performSelectorOnMainThread qui vient d'être dépilé par la runloop, par l'exécution d'un timer, ... va savoir. En tout cas bon courage :-/
  • Philippe49Philippe49 Membre
    10:12 modifié #4
    Merci pour ces précisions. Le plus curieux dans tout cela c'est que cela n'affecte pas l'application qui marche aussi bien. Le seul risque c'est que le free intempestif ait lieu à  un mauvais moment sur une zone qui aurait été réallouée.
    Tu adoptes quelque stratégie vis-à -vis du didReceiveMemoryWarning: ?
  • AliGatorAliGator Membre, Modérateur
    10:12 modifié #5
    Pour l'instant j'ai honte de n'en adopter aucune, j'avoue : c'est un truc que j'ai pas encore eu l'occasion de faire. C'est mal, surtout sur iPhone, mais justement ça fait partie des trucs que je vais commencer à  avoir à  coder pour les projets à  venir qui mettent en oeuvre des conditions de gestion mémoire un peu plus drastiques que mes projets précédents...

    En tout cas pour l'instant je n'ai jamais pris la peine de faire du StressTest sur mes applications et peu de Memory Allocations & Leaks tests (j'ai lancé Instruments pour vérifier les Leaks des fois, mais suis pas allé bcp plus loin dans l'analyse), d'autant que ce sont des applications qui n'ont encore jamais été publiées sur l'AppStore... mais il va falloir que je commence à  le faire sous peu car ce genre de cas va vite venir...
  • Philippe49Philippe49 Membre
    10:12 modifié #6
    dans 1244832151:

    Pour l'instant j'ai honte de n'en adopter aucune, j'avoue : c'est un truc que j'ai pas encore eu l'occasion de faire.


    Moi pareil  :o
  • Philippe49Philippe49 Membre
    10:12 modifié #7
    Avec iPhone 0s 3.,, on a trois versions du compilateurs : GCC 4.0, GCC 4.2, et GCC system version 4.2. Cela a-t-il une importance ?

    Il n'y a pas d'option Garbage Collector . Je ne l'utilise pas par ailleurs ( je ne me rappelle plus d'ailleurs si il est disponible sur iPhone ) mais je n'aimerais pas qu'il soit activé par défaut.
  • Philippe49Philippe49 Membre
    10:12 modifié #8
    dans 1244900522:

    Avec iPhone 0s 3.,, on a trois versions du compilateurs : GCC 4.0, GCC 4.2, et GCC system version 4.2. Cela a-t-il une importance ?

    Première réponse partielle : Avec GCC 4.0, UIKIT_EXTERN @interface UILocalizedIndexedCollation : NSObject ne passe pas
    GCC 4.2 est donc nécessaire.
  • Philippe49Philippe49 Membre
    juin 2009 modifié #9
    Si il y a quelqu'un de calé sur gdb qui passe ...
    Le message qui suit signifie bien que le programme (re)désalloue une variable entière ?


    CountItLite(1269,0xa0428720) malloc: *** error for object 0xe7ec10: double free
    *** set a breakpoint in malloc_error_break to debug

    (gdb) print 0xe7ec10
    $1 = 15199248          // c'est la valeur décimale de 0xe7ec10
    (gdb) whatis 0xe7ec10
    type = int


    Et est-ce que dans GCC 4.2, une telle instruction peut poser problème ?
    <br />	memcpy(values,(int[4]){1,2,3,4},4*sizeof(int));
    

  • zoczoc Membre
    10:12 modifié #10
    dans 1244907017:

    Et est-ce que dans GCC 4.2, une telle instruction peut poser problème ?
    <br />	memcpy(values,(int[4]){1,2,3,4},4*sizeof(int));
    



    Je savais même pas que ce genre d'écriture était acceptée par le compilateur  :P

    Je n'ai jamais utilisé de tableaux "inline" comme cela en 20 ans de programmation en C (je déclare le tableau comme n'importe quelle variable locale plutôt...), et c'est également la première fois que je le vois...
  • Philippe49Philippe49 Membre
    juin 2009 modifié #11
    Ce n'est pas loin de ma question. Le cast et les compound litteral n'ont rien d'original (on le fait très régulièrement pour les structures), mais il me semble avoir lu quelque part que GCC 4.2 transformait les constantes numériques présents dans le code en je ne sais trop quoi. Si cela était, et que la transformation utilise des variables dynamiques cela pourrait expliquer mon problème : qu'a donc GCC 4.2 de nouveau qui pourrait expliquer une erreur de gestion mémoire sur un int ?
  • Philippe49Philippe49 Membre
    10:12 modifié #12
    Ce que j'en ai conclut :

    dans 1244907017:

    Le message qui suit signifie bien que le programme (re)désalloue une variable entière ?

    CountItLite(1269,0xa0428720) malloc: *** error for object 0xe7ec10: double free
    *** set a breakpoint in malloc_error_break to debug

    (gdb) print 0xe7ec10
    $1 = 15199248          // c'est la valeur décimale de 0xe7ec10
    (gdb) whatis 0xe7ec10
    type = int


    Oui si la variable est toujours définie, ce qui est le cas si NSZombieEnabled est activée.

    dans 1244907017:

    Et est-ce que dans GCC 4.2, une telle instruction peut poser problème ?
    <br />	memcpy(values,(int[4]){1,2,3,4},4*sizeof(int));
    


    [/quote]
    Il n'y a pas de raison, c'est du C standard.



    dans 1244784849:

    malloc_error_break : double free  sur 0x..
    Je passe sur Instruments. le bug est difficile à  faire apparaà®tre ( 10-15 minutes), et j'ai une pile d'instructions qui finit par ... CFRunLoopRunInMode , CFRunLoopRunSpecific

    Bon, c'était une imbrication de timers mal agencée dans certaines configurations ...
Connectez-vous ou Inscrivez-vous pour répondre.