2010-08-19 8 views
5

Mam następujący fragment kodu:Czy Marshal.FreeHGlobal należy umieścić w bloku końcowym, aby zapewnić, że zasoby zostaną usunięte?

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

Jeżeli blok być zawinięte w próbie, a polecenie FreeHGlobal być umieszczony w końcu zablokować. (W przypadku, gdy polecenie środkowe zgłasza wyjątek).

Wydaje się, że ma to sens, aby w końcu zapobiec wyciekom pamięci w tym przypadku, jednak z przykładów, które znalazłem w Internecie, w końcu nie jest używany. Być może zasoby i tak zostaną automatycznie usunięte (nawet jeśli są niezarządzane).

Odpowiedz

12

Niezarządzana pamięć przydzielona z Marshal.AllocHGlobal nie jest automatycznie zwolniona.

więc oddanie Marshal.FreeHGlobal w finally bloku jest rzeczywiście dobry pomysł:

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

W znalazłeś zapewne przykłady pominąć błąd obsługi dla zwięzłości.


Jeśli przydzielania pamięci niezarządzanej do celów długoterminowych (tj nie zwalniając go w tej samej metody), może być zainteresowany owijania wskaźnik w obiekcie, który wywodzi się z SafeHandle (takich jak SafeBuffer) .

SafeHandle implementuje wzorzec IDisposable, dzięki czemu pamięć niezarządzana zostanie zwolniona po usunięciu obiektu lub gdy zbierający śmieci zbiera obiekt. SafeHandle wywodzi się również z klasy CriticalFinalizerObject, co oznacza, że ​​otrzyma specjalne traktowanie od CLR, aby upewnić się, że pamięć jest naprawdę uwolniona.

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; 
    } 
} 

Przykład:

using (var h = new HGlobal(buffer.Length)) 
{ 
    h.WriteArray(0, buffer, 0, buffer.Length); 
} 

Uwaga: SafeBuffer jest dość bestią, więc należy zachować ostrożność.

Uwaga 2: SafeHandles działa dobrze z P/Invoke i eliminuje potrzebę całkowitego omijania IntPtrs.

SafeBuffery służą do bezpiecznego manipulowania niezarządzaną pamięcią z C#, więc w zależności od tego, co robisz (przydzielanie niezarządzanej pamięci do użycia z P/Invoke lub manipulowanie niezarządzaną pamięcią z C#), należy odpowiednio wybrać SafeHandle lub SafeBuffer jako klasę podstawową .

2

Absolutnie. To nigdy zostaje automatycznie zwolniony, to pamięć niezarządzana.

Powiązane problemy