Es el tamaño de una matriz restringida por el límite superior del int (2147483647)?
-
05-09-2019 - |
Pregunta
Estoy haciendo ejercicios de algunos Proyecto Euler y me he topado con un escenario en el I he quieren matrices que son mayores que 2147483647 (el límite superior de int
en C #).
Por supuesto estos son grandes conjuntos, pero, por ejemplo, no pueden hacer esto
// fails
bool[] BigArray = new BigArray[2147483648];
// also fails, cannot convert uint to int
ArrayList BigArrayList = new ArrayList(2147483648);
Por lo tanto, puedo tener matrices más grandes?
EDIT: Era para una tamiz de Atkin , ya sabes, así que sólo quería uno realmente grande: D
Solución
En cualquier momento se está trabajando con una variedad tan grande, que probablemente debería tratar de encontrar una mejor solución al problema. Pero eso se dice que voy a seguir intentando responder a su pregunta.
Como se ha mencionado en este artículo existe es un límite de 2 GB en cualquier objeto en .NET. Para todos x86, x64 e IA64.
Al igual que con operativo Windows de 32 bits sistemas, hay un límite de 2 GB en el tamaño de un objeto puede crear mientras ejecutar una aplicación administrada de 64 bits en un sistema operativo Windows de 64 bits.
Además, si se define una matriz demasiado grande en la pila, tendrá un desbordamiento de pila. Si se define la matriz en el montón, intentará asignar todo en un solo bloque continuo grande. Sería mejor utilizar un ArrayList que tiene la asignación dinámica implícita en el montón. Esto no le permitirá conseguir más allá de los 2 GB, pero es probable que pueda estar más cerca de él.
Creo que el límite de tamaño de la pila será más grande sólo si está utilizando un x 64 o la arquitectura IA64 y sistema operativo. El uso de x64 o IA64 que tendrá la memoria asignable de 64 bits en lugar de 32 bits.
Si usted no es capaz de asignar la lista de arreglo de una sola vez, es probable que pueda asignarlo en partes.
El uso de una lista de arreglo y la adición de 1 objeto a la vez en una máquina x64 de Windows 2008 con 6 GB de RAM, lo máximo que se puede conseguir el ArrayList de tamaño es: 134217728. Así que realmente creo que hay que encontrar una mejor solución para su problema que no utiliza tanta memoria. Tal vez escribir en un archivo en lugar de utilizar la memoria RAM.
Otros consejos
El límite de matriz se, que yo sepa, fijado como int32 incluso en 64 bits. Hay un límite en el tamaño máximo de un único objeto. Sin embargo, usted podría tener una agradable gran matriz escalonada con bastante facilidad.
Peor; porque las referencias son más grandes en x64, para las matrices de tipo ref que en realidad obtener menor en una sola matriz.
aquí :
He recibido una serie de consultas, a por qué la versión de 64 bits de la 2,0 tiempo de ejecución .Net todavía tiene array máximo tamaños limitado a 2 GB. Teniendo en cuenta que se parece ser un tema candente en los últimos tiempos me descubierto un poco de historia y una discusión de las opciones para conseguir esta limitación estaba en orden.
En primer lugar algunos antecedentes; en el 2,0 versión del tiempo de ejecución .Net (CLR) que tomado una decisión consciente para el diseño mantener el tamaño máximo permitido objeto en el GC Montón a 2 GB, incluso en el versión de 64 bits del tiempo de ejecución. Esto es el mismo que el actual 1.1 implementación del CLR de 32 bits, sin embargo, sería difícil para En realidad gestionar asignar un 2 GB objeto sobre el CLR de 32 bits porque el espacio de direcciones virtuales es simplemente demasiado fragmentada de encontrar una manera realista 2GB agujero. En general, la gente no está particularmente preocupados con la creación tipos que serían> 2 GB cuando instancia (o en cualquier lugar cerca), sin embargo, desde las matrices son sólo una tipo especial de tipo administrado que son creado dentro del montón administrado se también sufren de esta limitación.
Cabe señalar que en .NET 4.5 el tamaño de la memoria límite se elimina opcionalmente por el gcAllowVeryLargeObjects bandera, sin embargo, esto no cambia el máximo dimensión tamaño. El punto clave es que si usted tiene matrices de un tipo personalizado, o matrices multidimensionales, entonces ahora se puede ir más allá de 2 GB de tamaño de memoria.
No es necesario un conjunto tan grande en absoluto.
Cuando el método se encuentra con problemas de recursos, no sólo buscar la forma de ampliar los recursos, mirar el método también. :)
Esta es una clase que utiliza un buffer de 3 MB para calcular números primos utilizando el criba de Eratóstenes. La clase mantiene un registro de los números primos hasta qué punto se han calculado, y cuando el rango debe ser ampliado crea un buffer para probar otros 3 millones de números.
Mantiene los números primos que se encuentran en una lista, y cuando se expande el rango de los números primos Previos se utilizan para descartar los números en la memoria intermedia.
he hecho algunas pruebas, y un tampón alrededor de 3 MB es más eficiente.
public class Primes {
private const int _blockSize = 3000000;
private List<long> _primes;
private long _next;
public Primes() {
_primes = new List<long>() { 2, 3, 5, 7, 11, 13, 17, 19 };
_next = 23;
}
private void Expand() {
bool[] sieve = new bool[_blockSize];
foreach (long prime in _primes) {
for (long i = ((_next + prime - 1L) / prime) * prime - _next;
i < _blockSize; i += prime) {
sieve[i] = true;
}
}
for (int i = 0; i < _blockSize; i++) {
if (!sieve[i]) {
_primes.Add(_next);
for (long j = i + _next; j < _blockSize; j += _next) {
sieve[j] = true;
}
}
_next++;
}
}
public long this[int index] {
get {
if (index < 0) throw new IndexOutOfRangeException();
while (index >= _primes.Count) {
Expand();
}
return _primes[index];
}
}
public bool IsPrime(long number) {
while (_primes[_primes.Count - 1] < number) {
Expand();
}
return _primes.BinarySearch(number) >= 0;
}
}
Creo que incluso dentro de un CLR de 64 bits, hay un límite de 2 GB (o, posiblemente, 1 GB - No puedo recordar exactamente) por objeto. Que impediría la creación de un conjunto más amplio. El hecho de que sólo toma Array.CreateInstance argumentos Int32 para tamaños sugiere también.
En una nota más amplia, sospecho que si necesita arreglos tan grande que realmente debe cambiar la forma en que está enfocando el problema.
Estoy en gran medida un novato con C # (es decir, el aprendizaje durante esta semana), así que no estoy seguro de los detalles exactos de cómo se implementa ArrayList. Sin embargo, yo supongo que como no se ha definido un tipo para el ejemplo ArrayList, entonces la matriz sería asignado como una serie de referencias a objetos. Esto bien podría significar que en realidad se está asignando 4-8GB de memoria dependiendo de la arquitectura.
Según MSDN , el índice de matriz de bytes no puede ser mayor que 2147483591. para .NET antes de 4.5 era también un límite de memoria para una matriz. En .NET 4.5 de este máximo es el mismo, pero para otros tipos que puede ser de hasta 2146435071.
Este es el código para la ilustración:
static void Main(string[] args)
{
// -----------------------------------------------
// Pre .NET 4.5 or gcAllowVeryLargeObjects unset
const int twoGig = 2147483591; // magic number from .NET
var type = typeof(int); // type to use
var size = Marshal.SizeOf(type); // type size
var num = twoGig / size; // max element count
var arr20 = Array.CreateInstance(type, num);
var arr21 = new byte[num];
// -----------------------------------------------
// .NET 4.5 with x64 and gcAllowVeryLargeObjects set
var arr451 = new byte[2147483591];
var arr452 = Array.CreateInstance(typeof(int), 2146435071);
var arr453 = new byte[2146435071]; // another magic number
return;
}