Поделиться через


OutOfMemoryException Класс

Определение

Исключение, которое выбрасывается при недостаточном объеме памяти для выполнения программы.

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
Наследование
OutOfMemoryException
Наследование
OutOfMemoryException
Производный
Атрибуты

Комментарии

OutOfMemoryException использует HRESULT COR_E_OUTOFMEMORY, который имеет значение 0x8007000E.

Список начальных значений свойств для экземпляра OutOfMemoryException, см. в разделе OutOfMemoryException конструкторы.

Примечание

Значение унаследованного Data свойства всегда nullравно .

Исключение OutOfMemoryException имеет две основные причины:

  • Вы пытаетесь развернуть StringBuilder объект за пределы длины, определенной его StringBuilder.MaxCapacity свойством.

  • Среда CLR не может выделить достаточно непрерывной памяти для успешного выполнения операции. Это исключение может быть вызвано любым назначением свойства или вызовом метода, требующего выделения памяти. Дополнительные сведения о причине OutOfMemoryException исключения см. в записи блога "Недостаточно памяти" Не ссылается на физическую память.

    Этот тип OutOfMemoryException исключения представляет собой катастрофический сбой. Если вы решили обработать исключение, следует включить catch блок, который вызывает Environment.FailFast метод для завершения работы приложения и добавления записи в журнал системных событий, как показано в следующем примере.

    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...
    

Ниже перечислены некоторые условия, при которых возникает исключение, и действия, которые можно предпринять для его устранения.

Вы вызываете StringBuilder.Insert метод .

Вы пытаетесь увеличить длину StringBuilder объекта сверх размера, указанного его StringBuilder.MaxCapacity свойством . В следующем примере показано OutOfMemoryException исключение, вызываемое вызовом StringBuilder.Insert(Int32, String, Int32) метода , когда в примере пытается вставить строку, которая приведет к превышению максимальной емкости свойства объекта Length .

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.

Для устранения ошибки можно выполнить одно из следующих действий:

Приложение выполняется как 32-разрядный процесс.

32-разрядные процессы могут выделять не более 2 ГБ виртуальной памяти пользовательского режима в 32-разрядных системах и 4 ГБ памяти виртуального пользовательского режима в 64-разрядных системах. Это может усложнить выделение достаточного объема непрерывной памяти средой CLR, если требуется большое выделение. В отличие от этого, 64-разрядные процессы могут выделять до 8 ТБИТ виртуальной памяти. Чтобы устранить это исключение, перекомпилируйте приложение для 64-разрядной платформы. Сведения о нацеливание на конкретные платформы в Visual Studio см. в разделе Практическое руководство. Настройка проектов для целевых платформ.

Ваше приложение выполняет утечку неуправляемых ресурсов

Хотя сборщик мусора может освободить память, выделенную для управляемых типов, он не управляет памятью, выделенной для неуправляемых ресурсов, таких как дескрипторы операционной системы (включая дескрипторы файлов, сопоставленные в памяти файлы, каналы, разделы реестра и дескрипторы ожидания), и блоки памяти, выделенные непосредственно вызовами API Windows или вызовами функций выделения памяти, таких как malloc. Типы, использующие неуправляемые ресурсы, IDisposable реализуют интерфейс .

Если вы используете тип, использующий неуправляемые ресурсы, обязательно вызовите его IDisposable.Dispose метод после завершения его использования. (Некоторые типы также реализуют метод, идентичный Close в функции методу Dispose .) Дополнительные сведения см. в разделе Использование объектов, реализующих IDisposable .

Если вы создали тип, использующий неуправляемые ресурсы, убедитесь, что вы реализовали шаблон Dispose и при необходимости предоставили метод завершения. Дополнительные сведения см. в разделах Реализация метода Dispose и Object.Finalize.

Вы пытаетесь создать большой массив в 64-разрядном процессе

По умолчанию среда CLR в .NET Framework не допускает отдельные объекты, размер которых превышает 2 ГБ. Чтобы переопределить это значение по умолчанию, можно использовать <параметр файла конфигурации gcAllowVeryLargeObjects> , чтобы включить массивы, общий размер которых превышает 2 ГБ. В .NET Core по умолчанию включена поддержка массивов размером более 2 ГБ.

Вы работаете с очень большими наборами данных (например, массивами, коллекциями или наборами данных базы данных) в памяти.

Если структуры данных или наборы данных, находящиеся в памяти, становятся настолько большими, что среда CLR не может выделить для них достаточно непрерывной памяти, возникает OutOfMemoryException исключение.

Чтобы избежать исключений OutOfMemoryException , необходимо изменить приложение, чтобы в памяти было меньше данных, или данные были разделены на сегменты, требующие меньшего объема памяти. Пример:

  • Если вы извлекаете все данные из базы данных, а затем фильтруете их в приложении, чтобы свести к минимуму количество обращений к серверу, следует изменить запросы, чтобы возвращать только подмножество данных, необходимых вашему приложению. При работе с большими таблицами несколько запросов почти всегда более эффективны, чем получение всех данных в одной таблице и последующее управление ими.

  • При динамическом выполнении запросов, создаваемых пользователями, следует убедиться, что количество записей, возвращаемых запросом, ограничено.

  • Если вы используете большие массивы или другие объекты коллекции, размер которых приводит к исключению OutOfMemoryException , следует изменить приложение, чтобы работать с данными в подмножествах, а не работать со всеми сразу.

В следующем примере возвращается массив, состоящий из 200 миллионов значений с плавающей запятой, а затем вычисляется их среднее значение. Выходные данные из примера показывают, что, поскольку в примере весь массив сохраняется в памяти перед вычислением среднего значения, 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.

В следующем примере исключение устраняется OutOfMemoryException путем обработки входящих данных без сохранения всего набора данных в памяти, сериализации данных в файл, если это необходимо, чтобы обеспечить дальнейшую обработку (эти строки закомментированы в примере, так как в этом случае они создают файл, размер которого превышает 1 ГБ), и возвращает вычисленное среднее и количество вариантов вызывающей подпрограмме.

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

Вы неоднократно сцепляете большие строки.

Так как строки являются неизменяемыми, каждая операция объединения строк создает новую строку. Влияние небольших строк или небольшого количества операций объединения незначительно. Но для больших строк или очень большого количества операций объединения строк объединение строк может привести к большому количеству выделений памяти и фрагментации памяти, снижению производительности и, возможно OutOfMemoryException , исключениям.

При объединении больших строк или выполнении большого количества операций объединения следует использовать StringBuilder класс вместо String класса . Завершив управление строкой, преобразуйте экземпляр в StringBuilder строку, вызвав StringBuilder.ToString метод .

Вы закрепляете большое количество объектов в памяти.

Закрепление большого количества объектов в памяти в течение длительного времени может затруднить сборщику мусора выделение смежных блоков памяти. Если вы закрепили большое количество объектов в памяти, например с помощью fixed инструкции в C# или путем вызова GCHandle.Alloc(Object, GCHandleType) метода с типом дескриптора GCHandleType.Pinned, можно выполнить следующие действия, чтобы устранить OutOfMemoryException исключение.

  • Оцените, требуется ли закрепление каждого объекта.

  • Убедитесь, что каждый объект откреплен как можно скорее.

  • Убедитесь, что каждый вызов GCHandle.Alloc(Object, GCHandleType) метода для закрепления памяти имеет соответствующий вызов GCHandle.Free метода для открепления этой памяти.

Следующие инструкции microsoft intermediate (MSIL) вызывают OutOfMemoryException исключение:

Конструкторы

OutOfMemoryException()

Инициализирует новый экземпляр класса OutOfMemoryException.

OutOfMemoryException(SerializationInfo, StreamingContext)
Устаревшие..

Инициализирует новый экземпляр класса OutOfMemoryException с сериализованными данными.

OutOfMemoryException(String)

Инициализирует новый экземпляр класса OutOfMemoryException с указанным сообщением об ошибке.

OutOfMemoryException(String, Exception)

Инициализирует новый экземпляр класса OutOfMemoryException указанным сообщением об ошибке и ссылкой на внутреннее исключение, вызвавшее данное исключение.

Свойства

Data

Возвращает коллекцию пар «ключ-значение», предоставляющую дополнительные сведения об исключении.

(Унаследовано от Exception)
HelpLink

Получает или задает ссылку на файл справки, связанный с этим исключением.

(Унаследовано от Exception)
HResult

Возвращает или задает HRESULT — кодированное числовое значение, присвоенное определенному исключению.

(Унаследовано от Exception)
InnerException

Возвращает экземпляр класса Exception, который вызвал текущее исключение.

(Унаследовано от Exception)
Message

Возвращает сообщение, описывающее текущее исключение.

(Унаследовано от Exception)
Source

Возвращает или задает имя приложения или объекта, вызывавшего ошибку.

(Унаследовано от Exception)
StackTrace

Получает строковое представление непосредственных кадров в стеке вызова.

(Унаследовано от Exception)
TargetSite

Возвращает метод, создавший текущее исключение.

(Унаследовано от Exception)

Методы

Equals(Object)

Определяет, равен ли указанный объект текущему объекту.

(Унаследовано от Object)
GetBaseException()

При переопределении в производном классе возвращает исключение Exception, которое является первопричиной одного или нескольких последующих исключений.

(Унаследовано от Exception)
GetHashCode()

Служит хэш-функцией по умолчанию.

(Унаследовано от Object)
GetObjectData(SerializationInfo, StreamingContext)
Устаревшие..

При переопределении в производном классе задает объект SerializationInfo со сведениями об исключении.

(Унаследовано от Exception)
GetType()

Возвращает тип среды выполнения текущего экземпляра.

(Унаследовано от Exception)
MemberwiseClone()

Создает неполную копию текущего объекта Object.

(Унаследовано от Object)
ToString()

Создает и возвращает строковое представление текущего исключения.

(Унаследовано от Exception)

События

SerializeObjectState
Устаревшие..

Возникает, когда исключение сериализовано для создания объекта состояния исключения, содержащего сериализованные данные об исключении.

(Унаследовано от Exception)

Применяется к

См. также раздел