2010-10-26 3 views
1

Quelqu'un peut-il expliquer ce qui se passe exactement à un niveau bas/perspective de gestion de la mémoire sur les lignes 2 C# dans "Main" dans ce qui suit?C# appelant la méthode C++ qui renvoie un pointeur. Expliquer la gestion de la mémoire

C++ code (non géré):

#define DLLEXPORT extern "C" __declspec(dllexport) 

    DLLEXPORT MyClass* MyClass_MyClass() 
    { 
     return new MyClass(); 
    } 
    DLLEXPORT void MyClass_setName(MyClass* myClass, const char* name) 
    { 
     myClass->setName(name); 
    } 

MyClass::MyClass() 
{ 
    _name.clear(); 
} 
void MyClass::setName(const char* name) 
{ 
    _name.setCString(name, NAME_MAX_BYTES); 
} 

C# Code:

 [DllImport(@"lib.dll")] 
     private static extern IntPtr MyClass_MyClass(); 
     [DllImport(@"lib.dll")] 
     public static extern void MyClass_setName(
        IntPtr myClass, 
        [System.Runtime.InteropServices.InAttribute()] 
        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] 
        string name); 

     public static void Main(string[] args) 
     { 
      var myClass = MyClass_MyClass(); 
      MyClass_setName(myClass , "Test Name"); 
     } 

Plus précisément, je me demande comment .NET ne sait beaucoup d'espace à allouer à "myClass"? Il doit faire une sorte de "Marshal.AllocHGlobal (SIZE)" en arrière-plan, non? Que se passe-t-il si plus d'espace est nécessaire (je donne un nom?)? De plus, y a-t-il un risque que la collecte des ordures se déplace et déplace la mémoire et gâche mon «IntPtr myClass»?

Répondre

1

.NET ne sait rien sur le type MyClass, il ne stocke qu'un pointeur. La taille du pointeur est toujours connue et fixée - 4 octets pour les processus 32 bits et 8 octets pour les processus 64 bits. Tous allocation de mémoire et de gestion dans ce cas particulier se produit dans le code C++ non géré ici:

return new MyClass(); 

et ici:

myClass->setName(name); 

Il est à ce C++ DLL pour décider comment allouer/gratuit/gérer la mémoire, Le code C# n'appellera que les fonctions importées de cette DLL.

Aucune récupération de place ne sera effectuée sur votre objet non géré et vous devrez fournir une méthode supplémentaire (non gérée) pour le libérer afin d'éviter les fuites de mémoire.

0

Si le code C++ n'est pas géré, .net n'alloue rien au-delà de IntPtr. Il est alloué par le code C++.

Cela signifie que la seule récupération de place sera faite sur ce IntPtr. Comme c'est petit, cela peut prendre beaucoup de temps avant que le garbage collector décide de le nettoyer. Cela signifie que même si votre code C++ nettoie bien après lui-même, cela peut prendre beaucoup de temps avant qu'il ne puisse réellement effectuer le nettoyage. Le code C++ utilise peut-être une tonne de mémoire, mais il est invisible pour .net, donc il ne le classera pas par ordre de priorité pour nettoyer les objets .net "plus gros".