La mémoire non gérée allouée avec Marshal.AllocHGlobal n'est pas libérée automatiquement.
Donc, mettre Marshal.FreeHGlobal dans un bloc finally
est en effet une bonne idée:
IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
try
{
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
SomeCommandThatCanThrowAnException();
}
finally
{
Marshal.FreeHGlobal(unmanagedPointer);
}
Les exemples que vous avez trouvé omettent probablement erreur de manipulation par souci de concision.
Si vous allouer de la mémoire à des fins non géré à long terme (c.-à-pas le libérer dans le même méthode), vous pourriez être intéressé par envelopper le pointeur dans un objet qui dérive de SafeHandle (comme SafeBuffer) .
SafeHandle implémente le modèle IDisposable, de sorte que la mémoire non managée sera libérée lorsque vous disposez de l'objet ou lorsque le garbage collector collecte l'objet. SafeHandle dérive également de la classe CriticalFinalizerObject ce qui signifie qu'il recevra un traitement spécial du CLR pour s'assurer que la mémoire est réellement libérée.
class HGlobal : SafeBuffer
{
public HGlobal(int cb)
: base(true)
{
this.SetHandle(Marshal.AllocHGlobal(cb));
this.Initialize((ulong)cb);
}
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(this.handle);
return true;
}
}
Exemple:
using (var h = new HGlobal(buffer.Length))
{
h.WriteArray(0, buffer, 0, buffer.Length);
}
Note: SafeBuffer est tout à fait une bête, si la prudence est conseillée.
Remarque 2: SafeHandles fonctionne bien avec P/Invoke et élimine le besoin de contourner complètement IntPtrs. Les SafeBuffers sont conçus pour manipuler en toute sécurité de la mémoire non managée à partir de C#, donc en fonction de ce que vous faites (allouer de la mémoire non managée à P/Invoke ou manipuler de la mémoire non managée), vous devez choisir SafeHandle ou SafeBuffer comme classe de base. .