Bueno como todos sabrán el pasado 12 de marzo se libero la nueva versión de java, y con ella varias mejoras que son la culminación de un trabajo arduo para llevar a java a ser un lenguaje que va a la vanguardia de las tecnologías modernas.

A partir de esta versión podremos comenzar a ver cambios mas increíbles que nos ayudaran a que nuestras aplicaciones java funcionen en un mundo que va dirigido hacia IoT, Cloud computing, IA y varios otros conceptos que podrían venir por defecto con el lenguaje.

Para una referencia completa en ingles, refiéranse a la publicación oficial:

https://openjdk.java.net/projects/jdk/12/

Yo por mi parte les dejo un resumen, como siempre, en buen castellano que espero pueda informarlos.

Shenandoah: Un garbage collector de baja pausa (Experimental)

Se agrego un nuevo algoritmo de garbage collection (GC) llamado Shenandoah que reduce los tiempos de pausa del GC haciendo un trabajo de evacuación de forma concurrente a los subprocesos de Java en ejecución. Los tiempos de pausa con Shenandoah son independientes del tamaño del heap, lo que significa que tendrá los mismos tiempos de pausa consistentes si su heap es de 200 MB o 200 GB.

Como característica experimental, Shenandoah requerirá -XX: + UnlockExperimentalVMOptions en la línea de comandos. El sistema de compilación Shenandoah desactiva la compilación en configuraciones no compatibles automáticamente. Los constructores intermedios pueden optar por deshabilitar la construcción de Shenandoah con –with-jvm-features = -shenandoahgc en plataformas compatibles.

Para habilitar / usar Shenandoah GC, se necesitarán las siguientes opciones de JVM: -XX: + UnlockExperimentalVMOptions -XX: + UseShenandoahGC.

Suite Microbenchmark

Agrega un conjunto básico de microbenchmarks al código fuente de JDK, y facilita a los desarrolladores la ejecución de microbenchmarks existentes y la creación de nuevos.

El conjunto de microbenchmark se ubicará junto con el código fuente de JDK en un solo directorio y, cuando se construya, producirá un solo archivo JAR. La ubicación conjunta simplificará la adición y ubicación de puntos de referencia durante el desarrollo. Al ejecutar los puntos de referencia, JMH proporciona potentes capacidades de filtrado que permiten al usuario ejecutar solo los puntos de referencia que son de interés actualmente. La ubicación exacta queda por determinar.

Las evaluaciones comparativas generalmente requieren comparaciones con una compilación anterior, o incluso una versión, por lo que las microbenchmarks deben ser compatibles con JDK (N), para las características de segmentación de benchmarks en el nuevo JDK, y JDK (N-1), para las características de benchmark de benchmarks existentes en una versión anterior. Esto significa, para JDK 12, que la estructura y los scripts de compilación deben ser compatibles con la compilación de puntos de referencia tanto para JDK 12 como para JDK 11. Los puntos de referencia se dividirán aún más mediante el uso de nombres de paquetes Java que describen el área del JDK que están probando.

Mejoras a las expresiones switch

Se extiende la instrucción switch para que se pueda usar como una declaración o una expresión, y para que ambas formas puedan usar un comportamiento de flujo de control y alcance “tradicional” o “simplificado”. Estos cambios simplificarán la codificación diaria y también prepararán el camino para el uso de pattern matching (JEP 305) en el switch. Esta es una característica del lenguaje de vista previa en JDK 12.

Además de los bloques switch “tradicionales”, se propone agregar una nueva forma “simplificada”, con las nuevas etiquetas de interruptor “case L ->”. Si una etiqueta coincide, entonces solo se ejecuta la expresión o declaración a la derecha de una etiqueta de flecha; no hay fallback por defecto. Por ejemplo, dado el método:

static void cuantos(int k) {
    switch (k) {
        case 1 -> System.out.println("uno");
        case 2 -> System.out.println("dos");
        case 3 -> System.out.println("muchos");
    }
}

El siguiente código:

howMany(1);
howMany(2);
howMany(3);

Resultará en lo siguiente:

uno
dos
muchos

Extenderemos la instrucción switch para que se pueda usar como expresión. En el caso común, una expresión de cambio se verá así:

T resultado = switch (arg) {
    case L1 -> expresion1;
    case L2 -> expresion2;
    default -> expresion3;
};

Una expresión de conmutación es una expresión polinomial; Si se conoce el tipo de objetivo, este tipo se empuja hacia abajo en cada case. El tipo de un switch es su tipo de destino, si se conoce; si no, se calcula un tipo independiente combinando los tipos de cada case.

La mayoría de las expresiones de conmutación tendrán una única expresión a la derecha de la etiqueta del conmutador “case L ->”. En el caso de que se necesite un bloque completo, se ha extendido la instrucción break para tomar un argumento, que se convierte en el valor de la expresión de conmutador adjunto.

int j = switch (dia) {
    case LUNES  -> 0;
    case MARTES -> 1;
    default      -> {
        int k = dia.toString().length();
        int resultado = f(k);
        break resultado;
    }
};

Una expresión switch puede, como una declaración de conmutación, también usar un bloque de conmutación “tradicional” con las etiquetas de conmutación “case L:” (lo que implica una semántica directa). En este caso, los valores se obtendrían utilizando la declaración break with value:

int result = switch (s) {
    case "Foo": 
        break 1;
    case "Bar":
        break 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        break 0;
};

API de constantes de la JVM

Se definió una familia de tipos de referencia simbólica basada en valores (JVMS 5.1), en el nuevo paquete java.lang.invoke.constant, capaz de describir cada tipo de constante cargable. Una referencia simbólica describe una constante cargable en forma puramente nominal, separada del contexto de accesibilidad o carga de clases. Algunas clases pueden actuar como sus propias referencias simbólicas (por ejemplo, String); para las constantes vinculables definimos una familia de tipos de referencia simbólicos (ClassDesc, MethodTypeDesc, MethodHandleDesc y DynamicConstantDesc) que contienen la información nominal para describir estas constantes.

Se puede encontrar un borrador de la especificación de la API aquí, y más información sobre su relación con las características en JEP 303 se puede encontrar en este documento complementario.

Un puerto AArch64, no dos

Existen dos puertos ARM de 64 bits en el JDK. Las principales fuentes de estos están en los directorios src/hotspot/cpu/arm y open/src/hotspot/cpu/aarch64. Aunque ambos puertos producen implementaciones aarch64, por el bien de este JEP, se refieren al primero, que fue aportado por Oracle, como arm64, y al último como aarch64.

Archivos CDS por defecto

Se modifico la compilación JDK para ejecutar java -Xshare: dump después de vincular la imagen. (Se pueden incluir opciones de línea de comandos adicionales para ajustar el tamaño del heap del GC, etc., a fin de obtener un mejor diseño de la memoria para casos comunes). los archivos CDS resultantes quedaron en el directorio lib/server, para que sea parte de La imagen resultante.

Los usuarios se beneficiarán de la función CDS automáticamente, ya que -Xshare: auto se habilitó de forma predeterminada para la máquina virtual del servidor en JDK 11 (JDK-8197967). Para deshabilitar CDS, ejecute con -Xshare: off.

Los usuarios con requisitos más avanzados (por ejemplo, utilizando listas de clases personalizadas que incluyen clases de aplicación, diferentes configuraciones de GC, etc.) todavía pueden crear un archivo de CDS personalizado como antes.

Colecciones Abortables Mixtas para G1

Si G1 descubre que las heurísticas de selección del conjunto de recopilación seleccionan repetidamente el número incorrecto de regiones, cambia a una forma más incremental de hacer recopilaciones mixtas: divide el conjunto de recopilación en dos partes, una obligatoria y una opcional. La parte obligatoria comprende partes del conjunto de recopilación que G1 no puede procesar de manera incremental (por ejemplo, las regiones jóvenes) pero también puede contener regiones antiguas para mejorar la eficiencia. Esto puede, por ejemplo, ser el 80% del conjunto de recopilación previsto. El 20% restante del conjunto de recopilación previsto, que consistirá solo de regiones antiguas, formará la parte opcional.

Después de que G1 termina de recolectar la parte obligatoria, G1 comienza a recolectar la parte opcional a un nivel mucho más granular, si queda tiempo. La granularidad de la recopilación de esta parte opcional depende de la cantidad de tiempo restante, como máximo de una región a la vez. Después de completar la recopilación de cualquier parte del conjunto de recopilación opcional, G1 puede decidir detener la recopilación en función del tiempo restante.

A medida que las predicciones vuelven a ser más precisas, la parte opcional de una colección se hace cada vez más pequeña, hasta que la parte obligatoria comprende una vez más todo el conjunto de la colección (es decir, G1 se basa completamente en sus heurísticas). Si las predicciones vuelven a ser inexactas, las próximas colecciones consistirán de nuevo en una parte obligatoria y otra opcional.

Mejoras ne devolución de la memoria comprometida no utilizada de G1

Para lograr el objetivo de devolver una cantidad máxima de memoria al sistema operativo, G1, durante la inactividad de la aplicación, intentará continuar o desencadenar un ciclo concurrente para determinar el uso general del heap de Java. Esto hará que devuelva automáticamente al sistema operativo las partes no utilizadas del heap de Java. Opcionalmente, bajo el control del usuario, se puede realizar un GC completo para maximizar la cantidad de memoria devuelta.

La aplicación se considera inactiva, y G1 activa una recolección de basura periódica si:

  • Más de G1PeriodicGCInterval milisegundos han pasado desde cualquier pausa de recolección de basura anterior y no hay ningún ciclo concurrente en progreso en este momento. Un valor de cero indica que las recolecciones de basura periódicas para reclamar rápidamente la memoria están deshabilitadas.
  • El valor promedio de carga del sistema de un minuto devuelto por la llamada getloadavg () en el sistema host JVM (por ejemplo, el contenedor) está por debajo de G1PeriodicGCSystemLoadThreshold. Esta condición se ignora si G1PeriodicGCSystemLoadThreshold es cero.

Categorized in:

Tagged in:

, , ,