Przeczytaj w języku angielskim

Udostępnij za pośrednictwem


OutOfMemoryException Klasa

Definicja

Wyjątek zgłaszany, gdy za mało pamięci, aby kontynuować wykonywanie programu.

public class OutOfMemoryException : Exception
public class OutOfMemoryException : SystemException
[System.Serializable]
public class OutOfMemoryException : SystemException
[System.Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class OutOfMemoryException : SystemException
Dziedziczenie
OutOfMemoryException
Dziedziczenie
OutOfMemoryException
Pochodne
Atrybuty

Uwagi

OutOfMemoryException używa COR_E_OUTOFMEMORYHRESULT, która ma wartość 0x8007000E.

Aby uzyskać listę początkowych wartości właściwości dla wystąpienia OutOfMemoryException, zobacz konstruktory OutOfMemoryException.

Uwaga

Wartość dziedziczonej właściwości Data jest zawsze null.

Wyjątek OutOfMemoryException ma dwie główne przyczyny:

  • Próbujesz rozwinąć obiekt StringBuilder poza długością zdefiniowaną przez jego właściwość StringBuilder.MaxCapacity.

  • Środowisko uruchomieniowe języka wspólnego nie może przydzielić wystarczającej ilości pamięci, aby pomyślnie wykonać operację. Ten wyjątek może zostać zgłoszony przez dowolne przypisanie właściwości lub wywołanie metody, które wymaga alokacji pamięci. Aby uzyskać więcej informacji na temat przyczyny wyjątku OutOfMemoryException, zobacz wpis w blogu "Brak pamięci" Nie odnosi się do pamięci fizycznej.

    Ten typ wyjątku OutOfMemoryException reprezentuje katastrofalną awarię. Jeśli zdecydujesz się obsłużyć wyjątek, należy uwzględnić blok catch, który wywołuje metodę Environment.FailFast, aby zakończyć działanie aplikacji i dodać wpis do dziennika zdarzeń systemu, jak w poniższym przykładzie.

    using System;
    
    public class Example
    {
       public static void Main()
       {
          try {
             // Outer block to handle any unexpected exceptions.
             try {
                string s = "This";
                s = s.Insert(2, "is ");
    
                // Throw an OutOfMemoryException exception.
                throw new OutOfMemoryException();
             }
             catch (ArgumentException) {
                Console.WriteLine("ArgumentException in String.Insert");
             }
    
             // Execute program logic.
          }
          catch (OutOfMemoryException e) {
             Console.WriteLine("Terminating application unexpectedly...");
             Environment.FailFast(String.Format("Out of Memory: {0}",
                                                e.Message));
          }
       }
    }
    // The example displays the following output:
    //        Terminating application unexpectedly...
    

Niektóre warunki, w których zgłaszany jest wyjątek, a akcje, które można podjąć, aby go wyeliminować, obejmują następujące elementy:

Wywołujesz metodę StringBuilder.Insert.

Próbujesz zwiększyć długość obiektu StringBuilder poza rozmiar określony przez jego właściwość StringBuilder.MaxCapacity. Poniższy przykład ilustruje wyjątek OutOfMemoryException zgłoszony przez wywołanie metody StringBuilder.Insert(Int32, String, Int32), gdy przykład próbuje wstawić ciąg, który spowoduje, że właściwość Length obiektu przekroczy maksymalną pojemność.

using System;
using System.Text;

public class Example
{
   public static void Main()
   {
      StringBuilder sb = new StringBuilder(15, 15);
      sb.Append("Substring #1 ");
      try {
         sb.Insert(0, "Substring #2 ", 1);
      }
      catch (OutOfMemoryException e) {
         Console.WriteLine("Out of Memory: {0}", e.Message);
      }
   }
}
// The example displays the following output:
//    Out of Memory: Insufficient memory to continue the execution of the program.

Aby rozwiązać ten problem, możesz wykonać jedną z następujących czynności:

Aplikacja jest uruchamiana jako proces 32-bitowy.

Procesy 32-bitowe mogą przydzielić maksymalnie 2 GB pamięci w trybie użytkownika wirtualnego w systemach 32-bitowych i 4 GB pamięci w trybie użytkownika wirtualnego w systemach 64-bitowych. Może to utrudnić środowisko uruchomieniowe języka wspólnego przydzielenie wystarczającej ilości ciągłej pamięci, gdy potrzebna jest duża alokacja. Natomiast 64-bitowe procesy mogą przydzielić do 8 TB pamięci wirtualnej. Aby rozwiązać ten wyjątek, ponownie skompiluj aplikację w celu kierowania platformy 64-bitowej. Aby uzyskać informacje na temat określania docelowych platform w programie Visual Studio, zobacz Instrukcje: konfigurowanie projektów na platformach docelowych.

Aplikacja przecieka niezarządzanych zasobów

Mimo że moduł odśmiecywania pamięci jest w stanie zwolnić pamięć przydzieloną do typów zarządzanych, nie zarządza pamięcią przydzieloną do niezarządzanych zasobów, takich jak dojścia systemu operacyjnego (w tym dojścia do plików, plików mapowanych pamięci, potoków, kluczy rejestru i uchwytów oczekiwania) oraz bloków pamięci przydzielonych bezpośrednio przez wywołania interfejsu API systemu Windows lub wywołań funkcji alokacji pamięci, takich jak malloc. Typy wykorzystujące niezarządzane zasoby implementują interfejs IDisposable.

Jeśli używasz typu korzystającego z zasobów niezarządzanych, po zakończeniu korzystania z niej należy wywołać metodę IDisposable.Dispose. (Niektóre typy implementują również metodę , która jest identyczna w funkcji z metodą ). Aby uzyskać więcej informacji, zobacz temat Using Objects That Implement IDisposable (Używanie obiektów implementujących IDisposable).

Jeśli utworzono typ używający zasobów niezarządzanych, upewnij się, że zaimplementowano wzorzec Dispose i, w razie potrzeby, podano finalizator. Aby uzyskać więcej informacji, zobacz Implementowanie metody Dispose i Object.Finalize.

Próbujesz utworzyć dużą tablicę w procesie 64-bitowym

Domyślnie środowisko uruchomieniowe języka wspólnego w programie .NET Framework nie zezwala na pojedyncze obiekty, których rozmiar przekracza 2 GB. Aby zastąpić tę wartość domyślną, możesz użyć ustawienia <gcAllowVeryLargeObjects> pliku konfiguracji, aby włączyć tablice, których całkowity rozmiar przekracza 2 GB. Na platformie .NET Core obsługa tablic większych niż 2 GB jest domyślnie włączona.

Pracujesz z bardzo dużymi zestawami danych (takimi jak tablice, kolekcje lub zestawy danych bazy danych) w pamięci.

Gdy struktury danych lub zestawy danych, które znajdują się w pamięci, stają się tak duże, że środowisko uruchomieniowe języka wspólnego nie może przydzielić wystarczającej ilości pamięci dla nich, wynik wyjątku OutOfMemoryException.

Aby zapobiec wyjątkom OutOfMemoryException, należy zmodyfikować aplikację tak, aby mniej danych mieściło się w pamięci lub dane zostały podzielone na segmenty wymagające mniejszych alokacji pamięci. Na przykład:

  • Jeśli pobierasz wszystkie dane z bazy danych, a następnie filtrujesz je w aplikacji, aby zminimalizować podróże do serwera, należy zmodyfikować zapytania tak, aby zwracały tylko podzestaw danych potrzebnych aplikacji. Podczas pracy z dużymi tabelami wiele zapytań jest prawie zawsze bardziej wydajnych niż pobieranie wszystkich danych w jednej tabeli, a następnie manipulowanie nimi.

  • Jeśli wykonujesz zapytania tworzone dynamicznie przez użytkowników, upewnij się, że liczba rekordów zwracanych przez zapytanie jest ograniczona.

  • Jeśli używasz dużych tablic lub innych obiektów kolekcji, których rozmiar powoduje wyjątek OutOfMemoryException, należy zmodyfikować aplikację, aby pracować z danymi w podzestawach, a nie pracować z nim jednocześnie.

Poniższy przykład pobiera tablicę składającą się z 200 milionów wartości zmiennoprzecinkowych, a następnie oblicza ich średnią. Dane wyjściowe z przykładu pokazują, że ponieważ przykład przechowuje całą tablicę w pamięci, zanim obliczy średnią, zostanie zgłoszony OutOfMemoryException.

using System;
using System.Collections.Generic;

public class Example
{
   public static void Main()
   {
      Double[] values = GetData();
      // Compute mean.
      Console.WriteLine("Sample mean: {0}, N = {1}",
                        GetMean(values), values.Length);
   }

   private static Double[] GetData()
   {
      Random rnd = new Random();
      List<Double> values = new List<Double>();
      for (int ctr = 1; ctr <= 200000000; ctr++) {
         values.Add(rnd.NextDouble());
         if (ctr % 10000000 == 0)
            Console.WriteLine("Retrieved {0:N0} items of data.",
                              ctr);
      }
      return values.ToArray();
   }

   private static Double GetMean(Double[] values)
   {
      Double sum = 0;
      foreach (var value in values)
         sum += value;

      return sum / values.Length;
   }
}
// The example displays output like the following:
//    Retrieved 10,000,000 items of data.
//    Retrieved 20,000,000 items of data.
//    Retrieved 30,000,000 items of data.
//    Retrieved 40,000,000 items of data.
//    Retrieved 50,000,000 items of data.
//    Retrieved 60,000,000 items of data.
//    Retrieved 70,000,000 items of data.
//    Retrieved 80,000,000 items of data.
//    Retrieved 90,000,000 items of data.
//    Retrieved 100,000,000 items of data.
//    Retrieved 110,000,000 items of data.
//    Retrieved 120,000,000 items of data.
//    Retrieved 130,000,000 items of data.
//
//    Unhandled Exception: OutOfMemoryException.

Poniższy przykład eliminuje wyjątek OutOfMemoryException przez przetwarzanie danych przychodzących bez przechowywania całego zestawu danych w pamięci, serializowanie danych do pliku w razie potrzeby w celu zezwolenia na dalsze przetwarzanie (te wiersze są komentowane w tym przykładzie, ponieważ w tym przypadku tworzą plik, którego rozmiar jest większy niż 1 GB) i zwraca średnią obliczeniową i liczbę przypadków do procedury wywoływania.

using System;
using System.IO;

public class Example
{
   public static void Main()
   {
      Tuple<Double, long> result = GetResult();
      Console.WriteLine("Sample mean: {0}, N = {1:N0}",
                        result.Item1, result.Item2);
   }

   private static Tuple<Double, long> GetResult()
   {
      int chunkSize = 50000000;
      int nToGet = 200000000;
      Random rnd = new Random();
      // FileStream fs = new FileStream(@".\data.bin", FileMode.Create);
      // BinaryWriter bin = new BinaryWriter(fs);
      // bin.Write((int)0);
      int n = 0;
      Double sum = 0;
      for (int outer = 0;
           outer <= ((int) Math.Ceiling(nToGet * 1.0 / chunkSize) - 1);
           outer++) {
         for (int inner = 0;
              inner <= Math.Min(nToGet - n - 1, chunkSize - 1);
              inner++) {
            Double value = rnd.NextDouble();
            sum += value;
            n++;
            // bin.Write(value);
         }
      }
      // bin.Seek(0, SeekOrigin.Begin);
      // bin.Write(n);
      // bin.Close();
      return new Tuple<Double, long>(sum/n, n);
   }
}
// The example displays output like the following:
//    Sample mean: 0.500022771458399, N = 200,000,000

Wielokrotnie łączysz duże ciągi.

Ponieważ ciągi są niezmienne, każda operacja łączenia ciągów tworzy nowy ciąg. Wpływ na małe ciągi lub niewielką liczbę operacji łączenia jest niewielki. Jednak w przypadku dużych ciągów lub bardzo dużej liczby operacji łączenia łączenie ciągów może prowadzić do dużej liczby alokacji pamięci i fragmentacji pamięci, niskiej wydajności i prawdopodobnie OutOfMemoryException wyjątków.

Podczas łączenia dużych ciągów lub wykonywania dużej liczby operacji łączenia należy użyć klasy StringBuilder zamiast klasy String. Po zakończeniu manipulowania ciągiem przekonwertuj wystąpienie StringBuilder na ciąg, wywołując metodę StringBuilder.ToString.

Przypinasz dużą liczbę obiektów w pamięci.

Przypinanie dużej liczby obiektów w pamięci przez długi czas może utrudnić modułowi odśmiecania pamięci przydzielanie ciągłych bloków pamięci. Jeśli przypięliśmy dużą liczbę obiektów w pamięci, na przykład przy użyciu instrukcji fixed w języku C# lub wywołując metodę GCHandle.Alloc(Object, GCHandleType) z typem uchwytu GCHandleType.Pinned, możesz wykonać następujące czynności, aby rozwiązać problem OutOfMemoryException wyjątku.

  • Oceń, czy każdy obiekt musi być przypięty,

  • Upewnij się, że każdy obiekt jest odpiętywany tak szybko, jak to możliwe.

  • Upewnij się, że każde wywołanie metody GCHandle.Alloc(Object, GCHandleType) w celu przypięcia pamięci ma odpowiednie wywołanie metody GCHandle.Free, aby odpiąć tę pamięć.

Następujące instrukcje dotyczące platformy Microsoft Intermediate (MSIL) zgłaszają wyjątek OutOfMemoryException:

  • box
  • newarr
  • newobj

Konstruktory

OutOfMemoryException()

Inicjuje nowe wystąpienie klasy OutOfMemoryException.

OutOfMemoryException(SerializationInfo, StreamingContext)
Przestarzałe.

Inicjuje nowe wystąpienie klasy OutOfMemoryException z serializowanymi danymi.

OutOfMemoryException(String, Exception)

Inicjuje nowe wystąpienie klasy OutOfMemoryException z określonym komunikatem o błędzie i odwołaniem do wyjątku wewnętrznego, który jest przyczyną tego wyjątku.

OutOfMemoryException(String)

Inicjuje nowe wystąpienie klasy OutOfMemoryException z określonym komunikatem o błędzie.

Właściwości

Data

Pobiera kolekcję par klucz/wartość, które zapewniają dodatkowe informacje zdefiniowane przez użytkownika dotyczące wyjątku.

(Odziedziczone po Exception)
HelpLink

Pobiera lub ustawia link do pliku pomocy skojarzonego z tym wyjątkiem.

(Odziedziczone po Exception)
HResult

Pobiera lub ustawia HRESULT, zakodowaną wartość liczbową przypisaną do określonego wyjątku.

(Odziedziczone po Exception)
InnerException

Pobiera wystąpienie Exception, które spowodowało bieżący wyjątek.

(Odziedziczone po Exception)
Message

Pobiera komunikat opisujący bieżący wyjątek.

(Odziedziczone po Exception)
Source

Pobiera lub ustawia nazwę aplikacji lub obiektu, który powoduje błąd.

(Odziedziczone po Exception)
StackTrace

Pobiera reprezentację ciągu natychmiastowych ramek na stosie wywołań.

(Odziedziczone po Exception)
TargetSite

Pobiera metodę, która zgłasza bieżący wyjątek.

(Odziedziczone po Exception)

Metody

Equals(Object)

Określa, czy określony obiekt jest równy bieżącemu obiektowi.

(Odziedziczone po Object)
GetBaseException()

Po zastąpieniu w klasie pochodnej zwraca Exception, która jest główną przyczyną co najmniej jednego kolejnego wyjątku.

(Odziedziczone po Exception)
GetHashCode()

Służy jako domyślna funkcja skrótu.

(Odziedziczone po Object)
GetObjectData(SerializationInfo, StreamingContext)
Przestarzałe.

Po zastąpieniu w klasie pochodnej ustawia SerializationInfo z informacjami o wyjątku.

(Odziedziczone po Exception)
GetType()

Pobiera typ środowiska uruchomieniowego bieżącego wystąpienia.

(Odziedziczone po Exception)
MemberwiseClone()

Tworzy płytkią kopię bieżącego Object.

(Odziedziczone po Object)
ToString()

Tworzy i zwraca reprezentację ciągu bieżącego wyjątku.

(Odziedziczone po Exception)

Zdarzenia

SerializeObjectState
Przestarzałe.

Występuje, gdy wyjątek jest serializowany w celu utworzenia obiektu stanu wyjątku zawierającego serializowane dane dotyczące wyjątku.

(Odziedziczone po Exception)

Dotyczy

Zobacz też