Marshal.FreeHGlobal devrait-il être placé dans un bloc final pour garantir que les ressources sont éliminées ?

StackOverflow https://stackoverflow.com/questions/3525932

Question

J'ai le bloc de code suivant :

IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
SomeCommandThatCanThrowAnException();
Marshal.FreeHGlobal(unmanagedPointer);

Le bloc doit-il être encapsulé dans un try et la commande FreeHGlobal doit-elle être placée dans un bloc final.(Au cas où la commande du milieu lèverait une exception).

Il semble logique que l'option final empêche les fuites de mémoire dans ce cas, mais d'après les exemples que j'ai trouvés en ligne, l'option enfin n'est pas utilisée.Peut-être que les ressources sont automatiquement supprimées de toute façon (même si elles ne sont pas gérées).

Était-ce utile?

La solution

La mémoire non gérée allouée avec Marshal.AllocHGlobal n'est pas automatiquement libérée.

Donc, mettre Marshal.FreeHGlobal dans un finally block 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és omettent probablement la gestion des erreurs par souci de concision.


Si vous allouez de la mémoire non gérée à des fins à long terme (par ex.sans le libérer au sein de la même méthode), vous pourriez être intéressé à envelopper le pointeur dans un objet dérivé de Poignée sûre (tel que Tampon de sécurité).

Poignée sûre implémente le modèle IDisposable, de sorte que la mémoire non gérée sera libérée lorsque vous supprimez l'objet ou lorsque le ramasse-miettes récupère l'objet.SafeHandle dérive également de la classe CriticalFinalizerObject, ce qui signifie qu'il bénéficiera d'un traitement spécial de la part 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 une véritable bête, la prudence est donc de mise.

Note 2:SafeHandles fonctionne bien avec P/Invoke et élimine le besoin de transmettre entièrement IntPtrs.

Les SafeBuffers permettent de manipuler en toute sécurité la mémoire non gérée à partir de C#, donc en fonction de ce que vous faites (allouer de la mémoire non gérée à utiliser avec P/Invoke ou manipuler de la mémoire non gérée à partir de C#), vous devez choisir SafeHandle ou SafeBuffer comme classe de base de manière appropriée.

Autres conseils

Tout à fait. Il jamais est libéré automatiquement, il est une mémoire non gérée.

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