Udostępnij za pośrednictwem


OutOfMemoryException Klasa

Definicja

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

public ref class OutOfMemoryException : Exception
public ref class OutOfMemoryException : SystemException
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
type OutOfMemoryException = class
    inherit Exception
type OutOfMemoryException = class
    inherit SystemException
[<System.Serializable>]
type OutOfMemoryException = class
    inherit SystemException
[<System.Serializable>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type OutOfMemoryException = class
    inherit SystemException
Public Class OutOfMemoryException
Inherits Exception
Public Class OutOfMemoryException
Inherits 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.

Nuta

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...
    
    open System
    
    try
        // Outer block to handle any unexpected exceptions.
        try
            let s = "This"
            let s = s.Insert(2, "is ")
    
            // Throw an OutOfMemoryException exception.
            raise (OutOfMemoryException())
        with
        | :? ArgumentException ->
            printfn "ArgumentException in String.Insert"
    
        // Execute program logic.
    with :? OutOfMemoryException as e ->
        printfn "Terminating application unexpectedly..."
        Environment.FailFast $"Out of Memory: {e.Message}"
    // The example displays the following output:
    //        Terminating application unexpectedly...
    
    Module Example
       Public Sub Main()
          Try
             ' Outer block to handle any unexpected exceptions.
             Try
                Dim s As String = "This"
                s = s.Insert(2, "is ")
    
                ' Throw an OutOfMemoryException exception.
                Throw New OutOfMemoryException()
             Catch e As ArgumentException
                Console.WriteLine("ArgumentException in String.Insert")
             End Try
             
             ' Execute program logic.
    
          Catch e As OutOfMemoryException
             Console.WriteLine("Terminating application unexpectedly...")
             Environment.FailFast(String.Format("Out of Memory: {0}",
                                                e.Message))
          End Try
       End Sub
    End Module
    ' 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.
open System
open System.Text

let sb = StringBuilder(15, 15)
sb.Append "Substring #1 "
|> ignore
try
    sb.Insert(0, "Substring #2 ", 1)
    |> ignore
with :? OutOfMemoryException as e ->
    printfn $"Out of Memory: {e.Message}"
// The example displays the following output:
//    Out of Memory: Insufficient memory to continue the execution of the program.
Imports System.Text

Module Example
   Public Sub Main()
      Dim sb As New StringBuilder(15, 15)
      sb.Append("Substring #1 ")
      Try
         sb.Insert(0, "Substring #2 ", 1)
      Catch e As OutOfMemoryException
         Console.WriteLine("Out of Memory: {0}", e.Message)
      End Try
   End Sub
End Module
' 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.
open System

let getData () =
    let rnd = Random()
    [|  for i = 1 to 200000000 do
            rnd.NextDouble()
            if i % 10000000 = 0 then
                printfn $"Retrieved {i:N0} items of data." |]
    
let getMean values =
    let sum = Array.sum values

    sum / float values.Length

let values = getData ()
// Compute mean.
printfn $"Sample mean: {getMean values}, N = {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.
Imports System.Collections.Generic

Module Example
   Public Sub Main()
      Dim values() As Double = GetData()
      ' Compute mean.
      Console.WriteLine("Sample mean: {0}, N = {1}",
                        GetMean(values), values.Length)
   End Sub
   
   Private Function GetData() As Double()
      Dim rnd As New Random()
      Dim values As New List(Of Double)()
      For ctr As Integer = 1 To 200000000
         values.Add(rnd.NextDouble)
         If ctr Mod 10000000 = 0 Then
            Console.WriteLine("Retrieved {0:N0} items of data.",
                              ctr)
         End If
      Next
      Return values.ToArray()
   End Function
   
   Private Function GetMean(values() As Double) As Double
      Dim sum As Double = 0
      For Each value In values
         sum += value
      Next
      Return sum / values.Length
   End Function
End Module
' 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
open System
// open System.IO

let getResult () =
    let chunkSize = 50000000
    let nToGet = 200000000
    let rnd = Random()
    // use fs = new FileStream(@".\data.bin", FileMode.Create)
    // use bin = new BinaryWriter(fs)
    // bin.Write 0
    let mutable n = 0
    let mutable sum = 0.
    for _ = 0 to int (ceil (nToGet / chunkSize |> float) - 1.) do
        for _ = 0 to min (nToGet - n - 1) (chunkSize - 1) do
            let value = rnd.NextDouble()
            sum <- sum + value
            n <- n + 1
            // bin.Write(value)
    // bin.Seek(0, SeekOrigin.Begin) |> ignore
    // bin.Write n
    sum / float n, n

let mean, n = getResult ()
printfn $"Sample mean: {mean}, N = {n:N0}"

// The example displays output like the following:
//    Sample mean: 0.500022771458399, N = 200,000,000
Imports System.IO

Module Example
   Public Sub Main()
      Dim result As Tuple(Of Double, Long) = GetResult()
      Console.WriteLine("Sample mean: {0}, N = {1:N0}",
                        result.Item1, result.Item2)
   End Sub

   Private Function GetResult As Tuple(Of Double, Long)
      Dim chunkSize As Integer = 50000000
      Dim nToGet As Integer = 200000000
      Dim rnd As New Random()
'       Dim fs As New FileStream(".\data.bin", FileMode.Create)
'       Dim bin As New BinaryWriter(fs)
'       bin.Write(CInt(0))
      Dim n As Integer
      Dim sum As Double
      For outer As Integer = 0 To CInt(Math.Ceiling(nToGet/chunkSize) - 1)
         For inner = 0 To Math.Min(nToGet - n - 1, chunkSize - 1)
            Dim value As Double = rnd.NextDouble()
            sum += value
            n += 1
'            bin.Write(value)
         Next
      Next
'       bin.Seek(0, SeekOrigin.Begin)
'       bin.Write(n)
'       bin.Close()
      Return New Tuple(Of Double, Long)(sum/n, n)
   End Function
End Module
' 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ż