try { // If no exception was thrown from map0, the address is valid addr = map0(imode, mapPosition, mapSize); } catch (OutOfMemoryError x) { // An OutOfMemoryError may indicate that we've exhausted memory // so force gc and re-attempt map System.gc(); try { Thread.sleep(100); } catch (InterruptedException y) { Thread.currentThread().interrupt(); } try { addr = map0(imode, mapPosition, mapSize); } catch (OutOfMemoryError y) { // After a second OOME, fail throw new IOException("Map failed", y); } }Desde jdk/FileChannelImpl.java en jdk8-b120 .
¿Esto ayuda con la recuperación de excepción?
En el ejemplo dado, el problema es memoria insuficiente. Por lo tanto, ejecutar el recolector de elementos no utilizados para liberar memoria podría solucionar este problema. Pero la llamada a System.gc() es solo una sugerencia para la JVM. No se garantiza que el recolector de basura libere memoria a través de esta llamada.
Así que este enfoque es algo así como una heurística.
Cuando la asignación de un objeto falla con un OutOfMemoryError , el recolector de basura ya hizo todo lo posible para recuperar la memoria de los objetos no utilizados o expandir el montón. Por lo tanto, llamar a System.gc() después de detectar OutOfMemoryError no tendría sentido.
Un caso especial es la situación en la que el recolector de elementos no utilizados reclama repetidamente una pequeña cantidad de memoria, por lo que la aplicación puede continuar, pero tiene que realizar otra recolección de elementos no utilizados justo en la siguiente asignación. Algunos recolectores de elementos no utilizados generan un OutOfMemoryError con el mensaje "Límite de gastos generales del GC excedido" cuando detectan que la aplicación dedicó más del 98 % del tiempo de CPU a la recolección de elementos no utilizados. En esta situación, llamar a System.gc() sería contraproducente, ya que entonces la aplicación dedica aún más tiempo a la recolección de basura además de crear y procesar OutOfMemoryError s.
El caso de FileChannelImpl es diferente. map0 puede fallar debido a una memoria nativa insuficiente o, en el caso de sistemas de 32 bits, cuando se queda sin espacio de direcciones. En estos casos, el administrador de memoria del montón no generó el OutOfMemoryError y es posible que el recolector de elementos no utilizados no se haya ejecutado. Pero para recuperar la memoria nativa o el espacio de direcciones, las instancias de ByteBuffer asociadas deben recolectar basura, para que su limpiador pueda ejecutarse. Este es un caso raro en el que llamar a System.gc(); tiene sentido.
Todavía es frágil, como System.gc(); no se garantiza que recopile todos los objetos o que ejecute el recolector de elementos no utilizados. Se supone que JEP 383 resuelve esto al proporcionar un mejor control sobre la vida útil de las asignaciones nativas.