¿Por qué aparece “No hay suficiente almacenamiento está disponible para procesar este comando” usando MappedByteBuffers Java?

StackOverflow https://stackoverflow.com/questions/1927123

  •  20-09-2019
  •  | 
  •  

Pregunta

Tengo una gran variedad de dobles que estoy usando un archivo basado en disco y una lista de búsqueda de MappedByteBuffers de manejar, ver esta pregunta para obtener más antecedentes. Estoy corriendo en Windows XP utilizando Java 1.5.

Esta es la parte clave de mi código que hace la asignación de los amortiguadores contra el archivo ...

try 
{
 // create a random access file and size it so it can hold all our data = the extent x the size of a double
 f = new File(_base_filename);
 _filename = f.getAbsolutePath();
 _ioFile = new RandomAccessFile(f, "rw");
 _ioFile.setLength(_extent * BLOCK_SIZE);
    _ioChannel = _ioFile.getChannel();

    // make enough MappedByteBuffers to handle the whole lot
 _pagesize = bytes_extent;
 long pages = 1;
 long diff = 0;
 while (_pagesize > MAX_PAGE_SIZE)
 {
  _pagesize  /= PAGE_DIVISION;
  pages *= PAGE_DIVISION;

  // make sure we are at double boundaries.  We cannot have a double spanning pages
  diff = _pagesize  % BLOCK_SIZE;
  if (diff != 0) _pagesize  -= diff;

 }

 // what is the difference between the total bytes associated with all the pages and the
 // total overall bytes?  There is a good chance we'll have a few left over because of the
 // rounding down that happens when the page size is halved
 diff = bytes_extent - (_pagesize  * pages);
 if (diff > 0)
 {
  // check whether adding on the remainder to the last page will tip it over the max size
  // if not then we just need to allocate the remainder to the final page
  if (_pagesize  + diff > MAX_PAGE_SIZE)
  {
   // need one more page
   pages++;
  }
 }

 // make the byte buffers and put them on the list
 int size = (int) _pagesize ;  // safe cast because of the loop which drops maxsize below Integer.MAX_INT
 int offset = 0;
 for (int page = 0; page < pages; page++)
 {
  offset = (int) (page * _pagesize );

  // the last page should be just big enough to accommodate any left over odd bytes
  if ((bytes_extent - offset) < _pagesize )
  {
   size = (int) (bytes_extent - offset);
  }

  // map the buffer to the right place 
     MappedByteBuffer buf = _ioChannel.map(FileChannel.MapMode.READ_WRITE, offset, size);

     // stick the buffer on the list
     _bufs.add(buf);
 }

 Controller.g_Logger.info("Created memory map file :" + _filename);
 Controller.g_Logger.info("Using " + _bufs.size() + " MappedByteBuffers");
    _ioChannel.close();
    _ioFile.close(); 
} 
catch (Exception e) 
{
 Controller.g_Logger.error("Error opening memory map file: " + _base_filename);
 Controller.g_Logger.error("Error creating memory map file: " + e.getMessage());
 e.printStackTrace();
 Clear();
    if (_ioChannel != null) _ioChannel.close();
    if (_ioFile != null) _ioFile.close();
 if (f != null) f.delete();
 throw e;
} 

consigo el error mencionado en el título después de asignar el segundo o tercer tampón.

pensé que era algo que ver con la memoria contiguo disponible, por lo que he intentado con diferentes tamaños y números de páginas, pero a ningún beneficio general.

¿Qué hace exactamente "No hay suficiente almacenamiento está disponible para procesar este comando" y lo que significa, en todo caso, puedo hacer al respecto?

pensé que el punto de MappedByteBuffers era la habilidad de ser capaz de manejar estructuras grandes de lo que podría caber en el montón, y tratarlos como si estuvieran en la memoria.

¿Alguna pista?

EDIT:

En respuesta a una respuesta más abajo (@adsk) He cambiado mi código por lo que nunca tienen más de un solo MappedByteBuffer activa en un momento dado. Cuando me refiero a una región del archivo que se encuentra actualmente sin asignar que la chatarra el mapa existente y crear una nueva. Sigo teniendo el mismo error después de unos 3 operaciones de correlación.

El fallo citado con GC no recoger los MappedByteBuffers todavía parece ser un problema en el JDK 1.5.

¿Fue útil?

Solución

  

pensé que el punto de MappedByteBuffers era la habilidad de ser capaz de manejar estructuras grandes de lo que podría caber en el montón, y tratarlos como si estuvieran en la memoria.

No. La idea es / era permitirá hacer frente a más de 2 ** 31 dobles ... en el supuesto de que tenía suficiente memoria, y estaban utilizando una JVM de 64 bits.

(estoy asumiendo que esto es una pregunta de seguimiento a esta pregunta .)

Editar . Claramente, se necesita más explicación

Hay una serie de límites que entran en juego.

  1. Java tiene una restricción fundamental que el atributo length de una matriz, y los índices de matriz tienen el tipo int. Esto, combinado con el hecho de que int se firma y una matriz no puede tener un tamaño negativo significa que la mayor variedad posible puede tener elementos 2**31. Esta restricción se aplica a 32 y 64 bits JVM. Es una parte fundamental del lenguaje Java ... como el hecho de que los valores van de char 0 a 65535.

  2. Uso de una JVM de 32 bits coloca un (teórico) límite superior de 2**32 sobre el número de bytes que son direccionables por la JVM. Esto incluye, todo el montón, su código y librerías de clases que se utiliza, el núcleo de código nativo de la JVM, memoria utilizada para buffers asignados ... todo. (De hecho, dependiendo de la plataforma, el sistema operativo puede le dará considerablemente menos de bytes 2**32 si el espacio de direcciones.)

  3. Los parámetros que se dan en la línea de comandos java determinar la cantidad de memoria de almacenamiento dinámico de la JVM permitir que utilice la aplicación. La memoria asignada a la utilización de objetos MappedByteBuffer no cuenta para esto.

  4. La cantidad de memoria que el sistema operativo le dará a usted depende (en Linux / UNIX) en la cantidad total de espacio de intercambio configurado, los límites de 'proceso' y así sucesivamente. Probablemente límites similares se aplican a Windows. Y, por supuesto, sólo se puede ejecutar una JVM de 64 bits si el sistema operativo anfitrión es capaz de 64 bits, y está utilizando un hardware capaz de 64 bits. (Si usted tiene un Pentium, que son sencillas de suerte.)

  5. Por último, la cantidad de memoria física de su sistema entra en juego. En teoría, puede preguntar a su JVM utilizar un montón, etc que es muchas veces más grande que la que la memoria física de la máquina. En la práctica, esto es un mala idea . Si el exceso de asignar la memoria virtual, el sistema se thrash y el rendimiento de la aplicación pasará por el suelo.

El quitará es la siguiente:

  • Si utiliza una JVM de 32 bits, es probable que esté limitado a algún lugar entre 2**31 y 2**32 bytes de memoria direccionable. Eso es suficiente espacio para un máximo de entre 2**29 y 2**30 dobles, si se utiliza una matriz o un búfer asignado.

  • Si utiliza una JVM de 64 bits, puede representar una única matriz de dobles 2**31. El límite teórico de un búfer asignado sería bytes o dobles 2**63 2**61, pero el límite práctico sería más o menos la cantidad de memoria física tiene su máquina.

Otros consejos

Al asignar la memoria un archivo, es posible que se quede sin espacio de direcciones de 32 bits VM. Esto ocurre incluso si el archivo se asigna en pequeños trozos y los ByteBuffers ya no son accesibles. La razón es que la GC no entra en acción para liberar los buffers.

Consulte el error en http://bugs.sun.com/bugdatabase /view_bug.do?bug_id=6417205

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top