2009-06-23 18 views
7

Antecedentes: estoy escribiendo un programa en C++ que trabaja con grandes cantidades de geodatos, y deseo cargar grandes fragmentos para procesar de una sola vez. Estoy obligado a trabajar con una aplicación compilada para máquinas de 32 bits. La máquina en la que estoy probando ejecuta un sistema operativo de 64 bits (Windows 7) y tiene 6 gigas de ram. El uso de MS VS 2008.¿Cuánta memoria debería poder asignar?

Tengo el siguiente código:

byte* pTempBuffer2[3]; 
try 
{ 
    //size_t nBufSize = nBandBytes*m_nBandCount; 
    pTempBuffer2[0] = new byte[nBandBytes]; 
    pTempBuffer2[1] = new byte[nBandBytes]; 
    pTempBuffer2[2] = new byte[nBandBytes]; 
} 
catch (std::bad_alloc) 
{ 
    // If we didn't get the memory just don't buffer and we will get data one 
    // piece at a time. 
    return; 
} 

Tenía la esperanza de que iba a ser capaz de asignar memoria hasta que la aplicación alcanza el límite de 4 gigabytes de 32 bits de direccionamiento. Sin embargo, cuando nBandBytes es 466,560,000, el nuevo lanza std :: bad_alloc en el segundo intento. En esta etapa, el valor del conjunto de trabajo (memoria) para el proceso es de 665,232 K. Por lo tanto, parece que no puedo obtener ni siquiera un registro de la memoria asignada.

Se mencionó un límite de 2 gigas para aplicaciones en Windows de 32 bits que puede ampliarse a 3 gigas con el modificador/3GB para win32. Este es un buen consejo en ese entorno, pero no es relevante para este caso.

¿Cuánta memoria debería poder asignar en el sistema operativo de 64 bits con una aplicación de 32 bits?

+0

Encontré esta referencia en la web: "Si está ejecutando una aplicación de 32 bits en un sistema operativo de 64 bits, obtendrá todo el espacio de direcciones 4G y todo eso podría estar respaldado por memoria física (si tener la memoria RAM) incluso sin ti mismo usando punteros de 64 bit ". del blog: http://blogs.msdn.com/ricom/archive/2009/06/10/visual-studio-why-is-there-no-64-bit-version.aspx – Bill

+0

En mi máquina de 32 bits, puedo asignar 466,560,000 × 3 bytes en una prueba simple. Parece que la memoria de proceso ya está fragmentada en el punto de asignación en su caso. –

+1

Me costó mucho elegir una respuesta para marcar correctamente en esta pregunta. Creo que la respuesta es complicada y depende de muchos factores. Los archivos mapeados en memoria son una buena respuesta, pero la causa principal de este problema parece ser la fragmentación de la memoria. bke1 señaló buenas herramientas para observar la memoria, y muchas personas hablaron sobre la fragmentación de la memoria, pero elegí la primera respuesta que establecía claramente el problema y establecía límites (4 Gigas por debajo de 64 bits y las banderas correctas). – Bill

Respuesta

10

Tanto como el sistema operativo quiere darle. De forma predeterminada, Windows permite que un proceso de 32 bits tenga 2 GB de espacio de direcciones. Y esto se divide en varios pedazos. Un área se reserva para la pila, otros para cada ejecutable y dll que se carga. Lo que quede se puede asignar dinámicamente, pero no hay garantía de que sea un gran bloque contiguo. Puede tratarse de varios trozos más pequeños de un par de cientos de MB cada uno.

Si se compila con la bandera LARGEADDRESSAWARE, Windows de 64 bits le permitirá utilizar el espacio de direcciones de 4 GB por completo, lo que debería ayudar un poco, pero en general,

  • usted no debe suponer que la disposición la memoria es contigua Debería poder trabajar con múltiples asignaciones más pequeñas en lugar de algunas grandes, y
  • Debe compilarla como una aplicación de 64 bits si necesita mucha memoria.
+0

"no debe suponer que la memoria disponible es contigua. Debería poder trabajar con múltiples asignaciones más pequeñas en lugar de algunas grandes, y" Esto está mal ya que Windows usa memoria paginada y para la aplicación es contigua para una gran pedazo – Lodle

+1

Lodle, usted está confundiendo el espacio de direcciones y el espacio libre de direcciones. P.ej. una de las formas más comunes de fragmentación es causada por su código en sí mismo. El EXE y las DLL no se cargan comenzando en 0x00000000. – MSalters

+0

@Lodle: No, la aplicación ve un espacio de direcciones contiguo, pero las variables exe, dll, stack y static se cargan en diferentes direcciones dentro de ese espacio de direcciones. – jalf

6

en Windows 32 bit, el proceso normal puede tomar 2 GB como máximo, pero con el interruptor /3GB puede alcanzar hasta 3 GB (para Windows 2003).

pero en su caso creo que está asignando memoria contigua, por lo que se produjo la excepción.

+3

+1 - nunca se consideró el hecho de que la asignación de una matriz contigua solo puede proporcionarle la mayor cantidad de memoria "contigua". Muy buen punto. –

+1

El modificador/3GB es un poco peligroso. Muchos controladores no se prueban con el conmutador, por lo que pueden volverse inestables cuando el sistema operativo está limitado a 1 GB. Sin embargo, no importa, ya que se está ejecutando en un Windows de 64 bits. – jalf

+1

Para ayudarme a entender lo que dices, intentaré y reformularlo. ¿Estás diciendo que si asigno la memoria en trozos más pequeños podré obtener más memoria total asignada? – Bill

1

Con nBandBytes en 466,560,000, está tratando de asignar 1,4 GB. Normalmente, una aplicación de 32 bits solo tiene acceso a 2 GB de memoria (más si arranca con/3GB y el ejecutable está marcado como un gran espacio de direcciones). Puede que le cueste encontrar tantos bloques de espacio de direcciones contiguos para sus grandes fragmentos de memoria.

Si desea asignar gigabytes de memoria en un sistema operativo de 64 bits, utilice un proceso de 64 bits.

+0

¿Cómo se obtiene 1.4GB? ¿Estás asumiendo que un byte sea de 4 bytes? : p – jalf

+0

3 * 466,560,000. Está asignando 3 matrices. – Michael

+0

Correcto, esperaba poder asignar 1.3 gigabytes de memoria, y me sorprendió cuando no pude. – Bill

1

Debe poder asignar un total de aproximadamente 2 GB por proceso. This article (PDF) explica los detalles. Sin embargo, probablemente no podrá obtener un solo bloque contiguo que esté cerca de ese tamaño.

1

Incluso si distribuye en trozos más pequeños, no podría obtener la memoria que necesita, especialmente si el programa circundante tiene un comportamiento de memoria impredecible, o si necesita ejecutar en diferentes sistemas operativos. En mi experiencia, el espacio de almacenamiento en un proceso de 32 bits limita a alrededor de 1,2 GB.

Con esta cantidad de memoria, recomendaría escribir manualmente en el disco. Envuelva sus matrices en una clase que administre la memoria y escriba en los archivos temporales cuando sea necesario. Es de esperar que las características de su programa sean tales que pueda almacenar efectivamente partes de esos datos en caché sin golpear demasiado el disco.

4

Puede asignar tanta memoria como su archivo de página le permita, incluso sin el modificador/3GB, puede asignar 4 GB de memoria sin mucha dificultad.

Lea this article para obtener una buena visión general de cómo pensar acerca de la memoria física, la memoria virtual y el espacio de direcciones (las tres cosas son diferentes). En pocas palabras, tienes exactamente tanta memoria física como RAM, pero tu aplicación realmente no tiene ninguna interacción con esa memoria física: es un lugar conveniente para almacenar los datos en tu memoria virtual. Su memoria virtual está limitada por el tamaño de su archivo de página, y la cantidad que su aplicación puede usar está limitada por la cantidad de otras aplicaciones que están usando (aunque puede asignar más, siempre que no la use realmente). Su espacio de direcciones en el mundo de 32 bits es de 4 GB. De ellos, 2 GB se asignan al kernel (o 1 GB si usa el modificador/3BG). De los 2 GB que quedan, algunos serán utilizados por tu stack, otros por el programa que estás ejecutando actualmente (y todos los dlls, etc.). Se va a fragmentar, y solo podrá obtener espacio contiguo: aquí es donde su asignación está fallando. Pero dado que ese espacio de direcciones es solo una forma conveniente de acceder a la memoria virtual que ha asignado para usted, es posible asignar mucha más memoria y traer porciones de ella a su espacio de direcciones unas pocas a la vez.

Raymond Chen has an example de cómo asignar 4 GB de memoria y asignar parte de ella en una sección de su espacio de direcciones.

En Windows de 32 bits, la asignación máxima es de 16TB y 256TB en Windows de 64 bits.

Y si realmente le interesa cómo funciona la administración de memoria en Windows, lea this article.

2

Durante el proyecto ElephantsDream, la Blender Foundation con Blender 3D tuvo problemas similares (aunque en Mac). No se puede incluir el enlace sino google: problema de asignación de memoria blender3d y será el primer elemento.

La solución implicó la asignación de archivos. No lo he probado pero puede leerlo aquí: http://msdn.microsoft.com/en-us/library/aa366556(VS.85).aspx

1

Sysinternals VMMap es ideal para investigar la fragmentación del espacio de direcciones virtuales, lo que probablemente limita la cantidad de memoria contigua que puede asignar. Recomiendo configurarlo para mostrar el espacio libre, luego ordenar por tamaño para encontrar las áreas libres más grandes, y luego ordenar por dirección para ver qué separa las áreas libres más grandes (probablemente DLL reestablecidas, regiones de memoria compartida u otros montones).

Evitar asignaciones contiguas extremadamente grandes es probablemente lo mejor, como otros han sugerido.

La configuración LARGE_ADDRESS_AWARE=YES (como se sugiere jalf) es buena, siempre y cuando las bibliotecas de las que depende su aplicación sean compatibles. Si lo hace, debe probar su código con la clave de registro AllocationPreference establecida para habilitar la asignación de direcciones virtuales descendentes.

+0

Buena idea - Voy a probar VMMap. – Bill