type - ¿Por qué recibo una Excepción de falta de memoria en mi aplicación C#?
system outofmemoryexception solucion (7)
Mi memoria es 4G física, pero ¿por qué tengo una excepción de memoria incluso si creo solo un objeto de memoria de 1.5G? ¿Alguna idea de por qué? (Vi al mismo tiempo, en la pestaña de rendimiento del administrador de tareas, que la memoria no está ocupada por completo, y también podría escribir aquí, así que la memoria no es realmente baja, así que creo que tengo otras limitaciones de memoria).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestBigMemoryv1
{
class MemoryHolderFoo
{
static Random seed = new Random();
public Int32 holder1;
public Int32 holder2;
public Int64 holder3;
public MemoryHolderFoo()
{
// prevent from optimized out
holder1 = (Int32)seed.NextDouble();
holder2 = (Int32)seed.NextDouble();
holder3 = (Int64)seed.NextDouble();
}
}
class Program
{
static int MemoryThreshold = 1500; //M
static void Main(string[] args)
{
int persize = 16;
int number = MemoryThreshold * 1000 * 1000/ persize;
MemoryHolderFoo[] pool = new MemoryHolderFoo[number];
for (int i = 0; i < number; i++)
{
pool[i] = new MemoryHolderFoo();
if (i % 10000 == 0)
{
Console.Write(".");
}
}
return;
}
}
}
Compruebe que está creando un proceso de 64 bits, y no uno de 32 bits, que es el modo de compilación predeterminado de Visual Studio. Para hacer esto, haga clic derecho en su proyecto, Propiedades -> Construir -> destino de la plataforma: x64. Como cualquier proceso de 32 bits, las aplicaciones de Visual Studio compiladas en 32 bits tienen un límite de memoria virtual de 2 GB.
Cada proceso tiene su propia memoria virtual, llamada espacio de direcciones, en la cual mapea el código que ejecuta y los datos que manipula. Un proceso de 32 bits utiliza punteros de dirección de memoria virtual de 32 bits, lo que crea un límite superior absoluto de 4 GB (2 ^ 32) para la cantidad de memoria virtual que puede abordar un proceso de 32 bits. Sin embargo, el sistema operativo requiere la mitad (para hacer referencia a su propio código y datos), creando un límite de 2 GB para cada proceso. Si su aplicación de 32 bits intenta consumir más de los 2 GB completos de su espacio de direcciones, devolverá "System.OutOfMemory", aunque la memoria física de su computadora no esté llena.
Los procesos de 64 bits no tienen esta limitación, ya que usan punteros de 64 bits, por lo que su espacio máximo de direcciones teórico es de 16 exabytes (2 ^ 64). En realidad, Windows x64 limita la memoria virtual de los procesos a 8TB. La solución al problema del límite de memoria es compilar en 64 bits.
Sin embargo, el tamaño del objeto en Visual Studio todavía está limitado a 2 GB, de forma predeterminada. Podrá crear varias matrices cuyo tamaño combinado será superior a 2 GB, pero no puede crear matrices de más de 2 GB de forma predeterminada. Con suerte, si aún desea crear matrices de más de 2 GB, puede hacerlo agregando el siguiente código a su archivo app.config:
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
En un sistema operativo Windows de 32 bits, la memoria máxima de "modo de usuario" a la que puede acceder una sola aplicación es de 2 GB ... suponiendo que tiene 4 GB de memoria en la caja.
Consumo de memoria de la aplicación VC ++ no administrada en el servidor de Windows
http://blogs.technet.com/markrussinovich/archive/2008/07/21/3092070.aspx
(Es gracioso que preguntes esto porque ayer pedí casi lo mismo ...)
En una aplicación de Windows normal de 32 bits, el proceso solo tiene 2 GB de memoria direccionable. Esto es irrelevante para la cantidad de memoria física disponible.
Así que 2 GB disponibles pero 1.5 es el máximo que puede asignar. La clave es que su código no es el único código que se ejecuta en el proceso. El otro .5 GB es probablemente la fragmentación más CLR en el proceso.
Actualización: en el proceso de .Net 4.5 en 64 bits puede tener matrices grandes si la configuración de gcAllowVeryLargeObjects está habilitada:
En plataformas de 64 bits, habilita las matrices que tienen más de 2 gigabytes (GB) de tamaño total. La cantidad máxima de elementos en una matriz es UInt32.MaxValue.
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
Solo adicional a los otros puntos; si desea acceder a una cantidad sucia de memoria, considere x64, pero tenga en cuenta que el tamaño máximo de objeto único sigue siendo de 2 GB. Y debido a que las referencias son mayores en x64, esto significa que en realidad obtiene un tamaño máximo de matriz / lista más pequeño para los tipos de referencia. ¡Por supuesto, cuando alcances ese límite probablemente estés haciendo las cosas mal de todos modos!
Otras opciones:
- usar archivos
- usa una base de datos
(obviamente, ambos tienen una diferencia de rendimiento en comparación con la memoria en proceso)
Actualización: en las versiones de .NET anteriores a 4.5, el tamaño máximo del objeto es de 2 GB. A partir de 4.5, puede asignar objetos más grandes si está habilitado gcAllowVeryLargeObjects . Tenga en cuenta que el límite para la string
no se ve afectado, pero las "matrices" también deberían cubrir las "listas", ya que las listas están respaldadas por matrices.
Solo para agregar a las respuestas anteriores: puede ir más allá del límite de 2 GB en los sistemas iniciados con las marcas de inicio / 3Gb [y opcionalmente conservar].
Tienes un máximo de 2Gb de memoria direccionable como una aplicación de 32 bits, como se mencionó en los otros pósters. No te olvides de los gastos generales. Está creando una matriz de 93 millones de objetos, si hay 4 bytes de sobrecarga por objeto que son 350Mb extra de memoria.
Una cosa más a tener en cuenta; algunos objetos .NET requieren memoria "contigua". es decir, si está intentando asignar una matriz grande, el sistema puede necesitar no solo suficiente memoria libre en su proceso sino también que toda la memoria libre esté en una gran porción ... y lamentablemente la memoria de proceso se fragmenta con el tiempo, por lo que puede no estar disponible
Algunos objetos / tipos de datos tienen este requisito y otros no ... No recuerdo cuáles lo hacen, pero me parece recordar que StringBuilder y MemoryStream tienen diferentes requisitos.