Question

Je reçois un NullReferenceException lors de l'exécution de mon application multi-thread, mais seulement quand je lance en mode de sortie en dehors du débogueur. La trace de la pile se connecté, et il pointe toujours au même appel de fonction. Je mets plusieurs déclarations de journalisation dans la fonction pour tenter de déterminer dans quelle mesure il obtiendrait, et chaque déclaration obtient ouvert une session, dont un sur la dernière ligne de la fonction. Ce qui est intéressant est que lorsque le NullReferenceException se produit, l'instruction après l'appel de fonction ne soit pas connecté:

    // ...
    logger.Log( "one" );  // logged
    Update( false );
    logger.Log( "eleven" );  // not logged when exception occurs
}

private void Update( bool condition )
{
    logger.Log( "one" );  // logged
    // ...  
    logger.Log( "ten" );  // logged, even when exception occurs
}

L'exception ne se produit pas à chaque fois que la fonction est appelée. Est-il possible que la pile est corrompu avant ou pendant l'exécution de la fonction telle que l'adresse de retour est perdu, ce qui entraîne dans la référence null? Je ne pensais pas ce genre de chose était possible sous .NET, mais je suppose que les choses étranges se sont produites.

J'ai essayé de remplacer l'appel à la fonction avec le contenu de la fonction, de sorte que tout se passe en ligne, et l'exception se produit alors sur une ligne qui ressemble à ceci:

foreach ( ClassItem item in classItemCollection )

J'ai vérifié par l'exploitation forestière que la « classItemCollection » est non nul, et j'ai aussi essayé de changer le foreach à un dans le cas où le IEnumerator faisait quelque chose de drôle, mais l'exception se produit sur la même ligne.

Toutes les idées sur la façon d'examiner cette question plus?

Mise à jour: Plusieurs intervenants ont proposé des solutions possibles ayant à voir avec l'enregistreur en vous assurant n'est pas nul. Pour être clair, les déclarations d'exploitation forestière ont été ajoutés à des fins de débogage après l'exception commencé à se produire.

Était-ce utile?

La solution

J'ai trouvé ma référence null. Comme Fredrik et micahtan suggéré, je ne l'ai pas fournir suffisamment d'informations pour la communauté de trouver une solution, donc je me suis dit que je devrais poster ce que je trouvais juste pour mettre cela pour se reposer.

Ceci est une représentation de ce qui se passait:

ISomething something = null;

//...

// the Add method returns a strong reference to an ISomething
// that it creates.  m_object holds a weak reference, so when
// "this" no longer has a strong reference, the ISomething can
// be garbage collected.
something = m_object.Add( index );

// the Update method looks at the ISomethings held by m_object.
// it obtains strong references to any that have been added,
// and puts them in m_collection;
Update( false );

// m_collection should hold the strong reference created by 
// the Update method.
// the null reference exception occurred here
something = m_collection[ index ];

return something;

Le problème est avéré être mon utilisation de la variable « quelque chose » comme une référence forte temporaire jusqu'à ce que la méthode de mise à jour a obtenu un poste permanent. Le compilateur, en mode de sortie, permet d'optimiser la distance « quelque chose = m_object.Add (); » mission, car « quelque chose » n'est pas utilisé jusqu'à ce qu'il soit assigné à nouveau. Cela a permis à l'ISomething soient nettoyés, il n'existait plus en m_collection quand j'ai essayé d'y accéder.

Tout ce que je devais faire était assurer que je tenais une référence forte qu'après l'appel mise à jour.

Je doute que ce sera d'aucune utilité pour personne, mais au cas où quelqu'un était curieux, je ne voulais pas laisser cette question sans réponse.

Autres conseils

Le fait qu'il enregistre « dix » me faire paraître d'abord à:

  • est logger jamais affecté ... est-ce peut-être en train de devenir nulle en quelque sorte
  • est le bogue dans Log lui-même

Difficile à dire sans contexte suffisant pour soit - mais comment je l'étudier. Vous pouvez également ajouter un test simple null quelque part; comme une approche insolente, vous pouvez renommer la méthode Log à quelque chose d'autre, et ajouter une méthode d'extension:

[Conditional("TRACE")]
public static void Log(this YourLoggerType logger, string message) {
    if(logger==null) {
       throw new ArgumentNullException("logger",
            "logger was null, logging " + message);
    } else {
       try {
           logger.LogCore(message); // the old method
       } catch (Exception ex) {
           throw new InvalidOperationException(
                "logger failed, logging " + message, ex);
       }
    }
}

Votre code existant doit appeler la nouvelle méthode d'extension de Log, et l'exception fera clairement exactement là où il barfed. Peut-être changer en arrière une fois fixe ... ou peut-être laisser.

D'accord w / Fredrik - plus de détails sont nécessaires. Un endroit pour commencer peut-être à la recherche: vous mentionnez l'application multi-thread et l'erreur se produit dans la version mais pas debug. Vous pourriez être en cours d'exécution dans un problème de synchronisation avec plusieurs threads d'accéder aux mêmes références d'objet.

Peu importe, je voudrais aussi probablement mettre un:

Debug.Assert(classItemCollection != null);

juste avant l'itération de la boucle. Il ne vous aidera pas en mode de libération, mais il peut vous aider à prendre le problème si (quand?) Il arrive dans Debug.

Je cherche un code qui est mise en enregistreur ou un de ses personnes à charge nulle. Y at-il des propriétés de bûcheron qui, lorsqu'il est réglé sur null, pourrait déclencher cela? Mode de sortie accélère parfois jusqu'à l'exécution de l'application qui peut révéler des problèmes de synchronisation qui sont masqués par la pénalité de performance du mode de mise au point et / ou le débogueur.

Le fait que « onze » ne reçoit pas me journalisés conduit à croire que l'enregistreur est réglé sur null juste avant cet appel est fait. Pouvez-vous envelopper dans un try / catch et de voir si elle touche la partie de capture du bloc? Peut-être que vous pouvez insérer un MessageBox.Show ou écrire quelque chose dans un fichier connu quand cela se produit.

modifions vous classItemCollection de plusieurs threads? Si vous changez la collection dans un autre thread que vous pouvez être invalidant le iterator qui pourrait conduire à une exception. Vous devrez peut-être protéger l'accès avec une serrure.

modifier: Pouvez-vous envoyer plus d'informations sur les types de CLASSITEM et classItemCollection?

Une autre possibilité est que CLASSITEM est un type de valeur et classItemCollection est une collection générique et en quelque sorte une valeur nulle est de s'ajouter à la collection. Ce qui suit jette une NullReferenceException:

        ArrayList list=new ArrayList();

        list.Add(1);
        list.Add(2);
        list.Add(null);
        list.Add(4);

        foreach (int i in list)
        {
            System.Diagnostics.Debug.WriteLine(i);
        }

Ce problème particulier peut être résolu par int? i ou i objet dans le foreach ou en utilisant un conteneur générique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top