OutOfMemoryException Třída
Definice
Důležité
Některé informace platí pro předběžně vydaný produkt, který se může zásadně změnit, než ho výrobce nebo autor vydá. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Výjimka, která je vyvolán, když není dostatek paměti pro pokračování v provádění 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
- Dědičnost
- Dědičnost
- Odvozené
- Atributy
Poznámky
OutOfMemoryException používá hodnotu HRESULT COR_E_OUTOFMEMORY
, která má hodnotu 0x8007000E.
Seznam počátečních hodnot vlastností pro instanci nástroje najdete v OutOfMemoryException konstruktorechOutOfMemoryException.
Poznámka
Hodnota zděděné Data vlastnosti je vždy null
.
Výjimka OutOfMemoryException má dvě hlavní příčiny:
Pokoušíte se rozšířit StringBuilder objekt za délku definovanou jeho StringBuilder.MaxCapacity vlastností.
Modul CLR (Common Language Runtime) nemůže přidělit dostatek souvislé paměti k úspěšnému provedení operace. Tuto výjimku může vyvolat jakékoli přiřazení vlastnosti nebo volání metody, které vyžaduje přidělení paměti. Další informace o příčině OutOfMemoryException výjimky najdete v blogovém příspěvku "Nedostatek paměti" Neodkazuje na fyzickou paměť.
Tento typ OutOfMemoryException výjimky představuje katastrofické selhání. Pokud se rozhodnete výjimku zpracovat, měli byste zahrnout
catch
blok, který volá metodu Environment.FailFast ukončení aplikace a přidá položku do protokolu systémových událostí, jak je tomu v následujícím příkladu.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...
Mezi podmínky, za kterých se výjimka vyvolá, a akce, které můžete provést k jejímu odstranění, patří:
Voláte metodu StringBuilder.Insert .
Pokoušíte se zvětšit délku objektu StringBuilder nad velikost určenou jeho StringBuilder.MaxCapacity vlastností. Následující příklad znázorňuje OutOfMemoryException výjimku vyvolanou voláním StringBuilder.Insert(Int32, String, Int32) metody, když se příklad pokusí vložit řetězec, který by způsobil, že vlastnost objektu Length překročí maximální kapacitu.
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.
Pokud chcete chybu vyřešit, můžete udělat jednu z následujících možností:
Nahraďte volání konstruktoru StringBuilder.StringBuilder(Int32, Int32) voláním jakéhokoli jiného StringBuilder přetížení konstruktoru. Maximální kapacita objektu StringBuilder bude nastavena na výchozí hodnotu, což je Int32.MaxValue.
StringBuilder.StringBuilder(Int32, Int32) Zavolejte konstruktor s
maxCapacity
hodnotou, která je dostatečně velká pro případná rozšíření objektuStringBuilder.
Vaše aplikace běží jako 32bitový proces.
32bitové procesy můžou přidělit maximálně 2 GB paměti virtuálního uživatelského režimu ve 32bitových systémech a 4 GB paměti virtuálního uživatelského režimu v 64bitových systémech. To může modulu ClR (Common Language Runtime) ztížit přidělení dostatečné souvislé paměti v případě, že je potřeba velké přidělení. Naproti tomu 64bitové procesy mohou přidělit až 8 TB virtuální paměti. Pokud chcete tuto výjimku vyřešit, překompilujte aplikaci tak, aby cílila na 64bitovou platformu. Informace o cílení na konkrétní platformy v sadě Visual Studio najdete v tématu Postupy: Konfigurace projektů na cílové platformy.
Vaše aplikace uniká nespravovanými prostředky
Přestože je systém uvolňování paměti schopen uvolnit paměť přidělenou spravovaným typům, nespravuje paměť přidělenou nespravovaným prostředkům, jako jsou popisovače operačního systému (včetně popisovačů souborů, souborů mapovaných na paměť, kanálů, klíčů registru a popisovačů čekání) a bloků paměti přidělených přímo voláním rozhraní API systému Windows nebo voláním funkcí přidělování paměti, jako malloc
je . Typy, které využívají nespravované prostředky, implementují IDisposable rozhraní.
Pokud používáte typ, který používá nespravované prostředky, měli byste po dokončení jeho použití volat jeho IDisposable.Dispose metodu. (Některé typy také implementují metodu Close
, která je ve funkci shodná s metodou Dispose
.) Další informace najdete v tématu Použití objektů, které implementují IDisposable .
Pokud jste vytvořili typ, který používá nespravované prostředky, ujistěte se, že jste implementovali model Dispose a v případě potřeby zadali finalizátor. Další informace najdete v tématech Implementace metody Dispose a Object.Finalize.
Pokoušíte se vytvořit velké pole v 64bitovém procesu.
Ve výchozím nastavení common language runtime v rozhraní .NET Framework nepovoluje jednotlivé objekty, jejichž velikost přesahuje 2 GB. Chcete-li přepsat toto výchozí nastavení, můžete použít nastavení konfiguračního <souboru gcAllowVeryLargeObjects> a povolit pole, jejichž celková velikost přesahuje 2 GB. V .NET Core je ve výchozím nastavení povolená podpora polí větších než 2 GB.
Pracujete s velmi velkými sadami dat (jako jsou pole, kolekce nebo databázové datové sady) v paměti.
Když datové struktury nebo datové sady, které se nacházejí v paměti, budou tak velké, že modul CLR (Common Language Runtime) pro ně nemůže přidělit dostatek souvislé paměti, dojde k výjimce OutOfMemoryException .
Pokud chcete těmto výjimkám OutOfMemoryException zabránit, musíte aplikaci upravit tak, aby v paměti bylo méně dat, nebo aby byla data rozdělena do segmentů, které vyžadují menší přidělení paměti. Příklad:
Pokud načítáte všechna data z databáze a pak je v aplikaci filtrujete, abyste minimalizovali cesty na server, měli byste upravit dotazy tak, aby vracely jenom podmnožinu dat, která vaše aplikace potřebuje. Při práci s velkými tabulkami je více dotazů téměř vždy efektivnější než načtení všech dat v jedné tabulce a následná manipulace s nimi.
Pokud provádíte dotazy, které uživatelé vytvářejí dynamicky, měli byste zajistit, aby byl počet záznamů vrácených dotazem omezený.
Pokud používáte velká pole nebo jiné objekty kolekce, jejichž velikost vede k výjimce OutOfMemoryException , měli byste aplikaci upravit tak, aby pracovala s daty v podmnožinách a nepracová s daty najednou.
Následující příklad získá matici, která se skládá z 200 milionů hodnot s plovoucí desetinnou čárkou, a pak vypočítá jejich střední hodnotu. Výstup z příkladu ukazuje, že vzhledem k tomu, že příklad ukládá celé pole do paměti před tím, než vypočítá průměr, OutOfMemoryException je vyvolána hodnota .
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.
Následující příklad eliminuje OutOfMemoryException výjimku tím, že zpracuje příchozí data bez uložení celé datové sady do paměti, serializuje data do souboru, pokud je to nutné, aby bylo možné další zpracování (tyto řádky jsou v příkladu zakomentovány, protože v tomto případě vytvářejí soubor s velikostí větší než 1 GB), a vrátí vypočítanou střední hodnotu a počet případů do rutiny volání.
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
Opakovaně zřetězení velkých řetězců.
Vzhledem k tomu, že řetězce jsou neměnné, každá operace zřetězení řetězců vytvoří nový řetězec. Dopad na malé řetězce nebo malý počet operací zřetězení je zanedbatelný. U velkých řetězců nebo velkého počtu operací zřetězení řetězců však může zřetězení řetězců vést k velkému počtu přidělení paměti a fragmentaci paměti, nízkému výkonu a možná OutOfMemoryException i k výjimkám.
Při zřetězení velkých řetězců nebo provádění velkého počtu operací zřetězení byste měli místo třídy použít StringBuilder třídu String . Po dokončení manipulace s řetězcem převeďte StringBuilder instanci na řetězec voláním StringBuilder.ToString metody .
Do paměti připnete velký počet objektů.
Připnutí velkého počtu objektů v paměti po dlouhou dobu může ztížit uvolňování paměti přidělení souvislých bloků paměti. Pokud jste v paměti připnuli velký počet objektů, například pomocí fixed
příkazu v jazyce C# nebo voláním GCHandle.Alloc(Object, GCHandleType) metody s typem GCHandleType.Pinnedpopisovače , můžete výjimku vyřešit OutOfMemoryException následujícím způsobem.
Vyhodnoťte, jestli je opravdu potřeba připnout každý objekt.
Ujistěte se, že každý objekt je co nejdříve odepnutý.
Ujistěte se, že každé volání GCHandle.Alloc(Object, GCHandleType) metody pro připnutí paměti má odpovídající volání GCHandle.Free metody pro odepnutí této paměti.
Následující pokyny microsoft intermediate (MSIL) vyvolají OutOfMemoryException výjimku:
Konstruktory
OutOfMemoryException() |
Inicializuje novou instanci OutOfMemoryException třídy. |
OutOfMemoryException(SerializationInfo, StreamingContext) |
Zastaralé.
Inicializuje novou instanci třídy OutOfMemoryException se serializovanými daty. |
OutOfMemoryException(String) |
Inicializuje novou instanci OutOfMemoryException třídy se zadanou chybovou zprávou. |
OutOfMemoryException(String, Exception) |
Inicializuje novou instanci OutOfMemoryException třídy se zadanou chybovou zprávou a odkazem na vnitřní výjimku, která je příčinou této výjimky. |
Vlastnosti
Data |
Získá kolekci párů klíč/hodnota, které poskytují další uživatelem definované informace o výjimce. (Zděděno od Exception) |
HelpLink |
Získá nebo nastaví odkaz na soubor nápovědy přidružené k této výjimce. (Zděděno od Exception) |
HResult |
Získá nebo nastaví HRESULT, kódovanou číselnou hodnotu, která je přiřazena ke konkrétní výjimce. (Zděděno od Exception) |
InnerException |
Exception Získá instanci, která způsobila aktuální výjimku. (Zděděno od Exception) |
Message |
Získá zprávu, která popisuje aktuální výjimku. (Zděděno od Exception) |
Source |
Získá nebo nastaví název aplikace nebo objektu, který způsobuje chybu. (Zděděno od Exception) |
StackTrace |
Získá řetězcovou reprezentaci okamžitých rámců v zásobníku volání. (Zděděno od Exception) |
TargetSite |
Získá metodu, která vyvolá aktuální výjimku. (Zděděno od Exception) |
Metody
Equals(Object) |
Určí, zda se zadaný objekt rovná aktuálnímu objektu. (Zděděno od Object) |
GetBaseException() |
Při přepsání v odvozené třídě vrátí Exception hodnotu, která je původní příčinou jedné nebo více následných výjimek. (Zděděno od Exception) |
GetHashCode() |
Slouží jako výchozí hashovací funkce. (Zděděno od Object) |
GetObjectData(SerializationInfo, StreamingContext) |
Zastaralé.
Při přepsání v odvozené třídě nastaví SerializationInfo s informacemi o výjimce. (Zděděno od Exception) |
GetType() |
Získá typ modulu runtime aktuální instance. (Zděděno od Exception) |
MemberwiseClone() |
Vytvoří mělkou kopii aktuálního Objectsouboru . (Zděděno od Object) |
ToString() |
Vytvoří a vrátí řetězcovou reprezentaci aktuální výjimky. (Zděděno od Exception) |
Událost
SerializeObjectState |
Zastaralé.
Nastane, když je výjimka serializována k vytvoření objektu stavu výjimky, který obsahuje serializovaná data o výjimce. (Zděděno od Exception) |