.NET Framework
Zarządzanie pamięcią
Szukaj…
Uwagi
Aplikacje krytyczne pod względem wydajności w zarządzanych aplikacjach .NET mogą mieć poważny wpływ na GC. Po uruchomieniu GC wszystkie pozostałe wątki są zawieszane, dopóki się nie zakończy. Z tego powodu zaleca się staranną ocenę procesów GC i ustalenie, jak zminimalizować ich działanie.
Niezarządzane zasoby
Kiedy mówimy o GC i „stercie”, naprawdę mówimy o tak zwanej sterowanej stercie . Obiekty na zarządzanej stercie mogą uzyskiwać dostęp do zasobów, które nie znajdują się na sterowanej stercie, na przykład podczas zapisu lub odczytu z pliku. Nieoczekiwane zachowanie może wystąpić, gdy plik zostanie otwarty do odczytu, a następnie wystąpi wyjątek, uniemożliwiający zamknięcie uchwytu pliku w normalny sposób. Z tego powodu .NET wymaga, aby niezarządzane zasoby implementowały interfejs IDisposable
. Ten interfejs ma jedną metodę o nazwie Dispose
bez parametrów:
public interface IDisposable
{
Dispose();
}
Podczas obsługi niezarządzanych zasobów należy upewnić się, że są one odpowiednio usuwane. Możesz to zrobić, wywołując jawnie funkcję Dispose()
w bloku na finally
lub za using
instrukcji using
.
StreamReader sr;
string textFromFile;
string filename = "SomeFile.txt";
try
{
sr = new StreamReader(filename);
textFromFile = sr.ReadToEnd();
}
finally
{
if (sr != null) sr.Dispose();
}
lub
string textFromFile;
string filename = "SomeFile.txt";
using (StreamReader sr = new Streamreader(filename))
{
textFromFile = sr.ReadToEnd();
}
Ta ostatnia jest preferowaną metodą i jest automatycznie rozszerzana do pierwszej podczas kompilacji.
Używaj SafeHandle podczas pakowania niezarządzanych zasobów
Pisząc opakowania dla niezarządzanych zasobów, powinieneś SafeHandle
zamiast próbować samodzielnie wdrożyć IDisposable
i finalizator. Twoja podklasa SafeHandle
powinna być tak mała i prosta, jak to możliwe, aby zminimalizować ryzyko wycieku uchwytu. Prawdopodobnie oznacza to, że twoja implementacja SafeHandle byłaby wewnętrznym szczegółem implementacji klasy, która ją otacza, zapewniając użyteczny interfejs API. Ta klasa zapewnia, że nawet jeśli program SafeHandle
instancji SafeHandle
, niezarządzany uchwyt zostanie zwolniony.
using System.Runtime.InteropServices;
class MyHandle : SafeHandle
{
public override bool IsInvalid => handle == IntPtr.Zero;
public MyHandle() : base(IntPtr.Zero, true)
{ }
public MyHandle(int length) : this()
{
SetHandle(Marshal.AllocHGlobal(length));
}
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
return true;
}
}
Oświadczenie: Ten przykład jest próbą pokazania, jak chronić zarządzany zasób za pomocą SafeHandle
który implementuje IDisposable
i odpowiednio konfiguruje finalizatory. Przypisywanie fragmentu pamięci w ten sposób jest bardzo przemyślane i prawdopodobnie nie ma sensu.