2010-12-07 46 views
1

J'ai un composant COM écrit en VB6 que j'utilise depuis une application Visual Basic .NET via COM interop.Pourquoi mon composant COM lance OutOfMemoryException, mais fonctionne correctement sur VB6?

Il existe une méthode qui déclenche une exception OutOfMemoryException lorsqu'elle est appelée à partir de VB.NET. Toutefois, lorsque je cours le même appel à partir d'une application Visual Basic 6, tout fonctionne correctement.

Je ne peux pas poster de code ici parce qu'il est trop long et difficile à suivre (je suis chargé de le réparer) et je ne peux pas identifier le problème, car lorsque j'essaie de le déboguer de VB6, l'erreur ne t montrer.

Qu'est-ce qui pourrait causer ce comportement distinct?

Cela fonctionnait correctement jusqu'à ce que j'ai résolu un problème de performances à l'aide d'un objet Dictionary (un COM de Microsoft Scripting Runtime). À moins que le dictionnaire ne se développe de manière irrationnelle ou fuit, je ne vois pas comment cela pourrait causer cela, puisqu'il ne dépasse jamais 100-200 éléments et qu'un seul est créé avant que l'exception ne soit lancée.

J'ai essayé le même correctif avec un objet Collection et une fonction Exists() maladroite et le même problème se produit. Si je rentre tôt en retournant Nothing, cela fonctionne (c'est-à-dire, il renvoie NullReferenceException, comme prévu).

+0

Existe-t-il une pile de pile significative? et qu'en est-il de la mémoire? Quelle est la taille du processus? –

+0

@Simon: stacktrace se termine à la limite COM/.NET. Le processus est d'environ 100 Mo lorsque l'exception survole la pile. –

+0

L'objet COM Scripting.Dictionary est marqué comme STA (Appartement), comme indiqué ci-dessous par weloytty, avez-vous vérifié le filetage? Et BTW, accédez-vous à ce dictionnaire en utilisant plusieurs threads? –

Répondre

1

La gestion de la mémoire dans VB.NET est très différente. VB6 utilise le comptage de références pour libérer des objets COM, VB.NET utilise le garbage collector. Vous pouvez vous retrouver dans une situation, en particulier lorsque vous testez le composant, où le CPG n'est pas exécuté assez fréquemment pour libérer les objets COM. Ces objets allouent de la mémoire non gérée, ce qui ne fait pas pression sur le garbage collector pour lancer une collection. Commencez à diagnostiquer cela avec Perfmon.exe, Analyseur de performances. Cliquez avec le bouton droit sur le graphique, Ajouter des compteurs et sélectionnez .NET CLR Memory, # Gen 0 collections et choisissez votre processus. Vérifiez que vous voyez le compteur incrémenter à un taux raisonnable, au moins une seconde.

La résolution d'un tel problème est assez désagréable, assurez-vous qu'il ne s'agit pas d'un problème artificiel provoqué par l'isolation du composant. Ou un bug simple dans votre code, gardant une référence à l'objet COM. L'appel de GC.Collect() suivi de GC.WaitForPendingFinalizers() libérera les objets COM. Il en est de même pour Marshal.ReleaseComObject(). Utiliser GC.AddMemoryPressure() est également une solution de contournement possible, mais vous devez avoir une idée raisonnable de la quantité de mémoire non gérée requise par l'objet COM.

+0

Un bogue dû à la présence d'une référence à l'objet COM est peu probable, car je n'ai pas touché la partie .NET du code. En utilisant perfmon, j'ai vu très peu de collections au cours d'une exécution: il n'y avait que 10 collections gen 0 et 2 sur gen 2 avant le lancement. Pour l'instant j'ai corrigé le problème en poussant le correctif de performance jusqu'aux couches .NET ... –