El entrevistador te pregunta JVM, ¿sabes dónde están los puntos extra?

Introducción

En el proceso de entrevistar a otros, ​JVM 内存模型​casi siempre  pregunta, aunque algunas personas dicen que esas son las preguntas ​面试造航母,工作拧螺丝​. Si desea ser un codificador CRUD, puede optar por no saberlo.

En las preguntas y respuestas sobre el modelo de memoria JVM, algunas personas pueden decir que los objetos se asignan en el montón. Pero cuando pregunté si los objetos debían almacenarse en el montón, la mayoría de las personas respondieron que sí o dudaron.

De hecho, es correcto responder que al objeto se le asigna almacenamiento en el montón. Pero con el desarrollo de compiladores justo a ​JIT​tiempo y la madurez gradual de las técnicas de análisis de escape, se ha vuelto gradualmente menos absoluto que todos los objetos se asignen en el montón. ​, ​ ​​y ​栈上分配​  otras técnicas de optimización sufren algunos cambios sutiles.​标量替换​​锁消除​

Sabemos que el código fuente de Java que escribimos se ​javac​compila en un archivo de código de bytes, y luego el cargador de clases carga el archivo de código de bytes en la memoria, y la JVM lee e interpreta el código de bytes línea por línea y lo traduce a las instrucciones de máquina correspondientes para su ejecución. Obviamente, la ejecución interpretada es mucho más lenta que los programas binarios ejecutables directamente, como los programas C.

Entonces, para mejorar la eficiencia, se introdujo la tecnología de optimización JIT (compilador justo a tiempo). Los programas Java aún serán interpretados y ejecutados por el intérprete, pero si un método o bloque de código se ejecuta con frecuencia, la JVM ​热点代码​lo y luego traduce el código activo en instrucciones de la máquina local, lo optimiza, lo almacena en caché y lo descarga. Cuando vuelva a ejecutar este código, ejecútelo directamente sin más explicaciones.

Una técnica de optimización muy importante en JIT es el análisis de escape.

análisis de escape

El análisis de escape es en realidad analizar si un objeto escapará del método y analizar el alcance dinámico del objeto. Si un objeto se define dentro de un método y es probable que lo utilicen referencias fuera del método, se considera que se ha escapado.

Por ejemplo, el siguiente objeto de persona se escapa, es decir, se puede hacer referencia a él fuera del método.

public Person personEscape() { 
  Person person = new Person(); 
  persona de retorno; 
}

Entonces, ¿por qué escapar del análisis? De hecho, el objetivo final es optimizar el programa y mejorar el rendimiento de carrera. Existen los siguientes puntos técnicos de optimización:

  • asignación de pila
  • sustitución escalar
  • eliminación de bloqueo

A partir de JDK1.7, el análisis de escape está habilitado de forma predeterminada y se puede iniciar y detener a través de los siguientes parámetros.

# Habilitar 
-XX:+DoEscapeAnalysis 
# Deshabilitar 
-XX:-DoEscapeAnalysis

asignación de pila

Si se analiza un objeto y no hay un método de escape, puede colocarse en la pila. Esto elimina la necesidad de recopilaciones de GC en el montón, lo que mejora el rendimiento.

paquete com.chenpi; 

/** 
 * @Description 
 * @Author 陈皮
 * @Date 2021/7/14 
 * @Version 1.0 
 */ 
public class EscapeAnalysisTest { 

  public static void main(String[] args) { 

    long startTime = System.currentTimeMillis(); 

    for (int i = 0; i < 10000000; i++) { 
      stackAlloc(); 
    } 

    System.out.println((System.currentTimeMillis() - startTime) + "ms"); 
  } 

  public static void stackAlloc() { 
    Persona persona = nueva Persona("陈皮", 18); 
  } 

} 

class Persona { 

  private String nombre; 
  larga edad privada; 
    esta.edad = edad;

  public Person(String name, long age) {
    este.nombre = nombre; 
  } 
}

La configuración de parámetros de la máquina virtual permite el análisis de escape e imprime registros de GC.

-Xms200m -Xmx200m -XX:+HacerEscapeAnalysis -XX:+ImprimirGC

El resultado de ejecutar el programa es el siguiente, el consumo solo toma 10 ms y no hay GC.

10ms

Desactive el análisis de escape e imprima el registro del GC.

-Xms200m -Xmx200m -XX:-DoEscapeAnalysis -XX:+ImprimirGC

Los resultados de ejecutar el programa son los siguientes, el tiempo de consumo ha aumentado más de 10 veces y está acompañado por múltiples GC.

[GC (fallo de asignación) 51712K->784K(196608K), 0,0050396 s] 
[GC (fallo de asignación) 52496K->784K(196608K), 0,0030730 s] 
[GC (fallo de asignación) 52496K->752K(196608K), 0,0013993 s ] 
[GC (fallo de asignación) 52464K->720K(196608K), 0,0018371 segundos] 
176 ms

sustitución escalar

  • Escalar: un tipo que no se puede descomponer en datos más pequeños, como el tipo de datos básico es un escalar.
  • Agregado: un tipo de datos que se puede descomponer en otros agregados o escalares, como tipos de referencia de objetos.

Si un objeto no escapa, el JIT puede optimizar la descomposición del objeto en varios escalares. Esta es la sustitución escalar.

public void scalarReplace() { 
  Coordenadas coordenadas = nuevas coordenadas (105.10, 80.22); 
  System.out.println(coordenadas.longitud); 
  System.out.println(coordenadas.latitud); 
}

El programa de demostración anterior, el objeto de coordenadas no se escapa, por lo que el compilador JIT puede usar la sustitución escalar para la optimización. Finalmente, se optimiza en el siguiente programa.

escalarReplace public void() { 
  System.out.println(105.10); 
  Sistema.salida.println(80.22); 
}

De hecho, en la máquina virtual existente, no existe una implementación real de asignación de pila, pero en realidad se implementa mediante reemplazo escalar.

eliminación de bloqueo

¿Por qué quitar la cerradura? Debido a que el bloqueo reducirá el rendimiento, es mejor no bloquearlo. Si se analiza que el objeto bloqueado no escapará, es decir, solo puede ser accedido por un hilo, JIT puede optimizar y eliminar el bloqueo. También conocido como elisión síncrona.

public void lockRemove() { 
  sincronizado (nuevo objeto()) { 
    System.out.println("¡Soy Chen Pi!"); 
  } 
}

En el programa de demostración anterior, el objeto Object no se escapará, por lo que solo se puede acceder a él mediante el subproceso actual, por lo que el compilador JIT puede eliminar los bloqueos de optimización. Finalmente, se optimiza en el siguiente programa.

public void lockRemove() { 
  System.out.println("¡Soy Chen Pi!"); 
}

Resumir

Pero con el desarrollo de compiladores justo a ​JIT​tiempo y la madurez gradual de las técnicas de análisis de escape, se ha vuelto gradualmente menos absoluto que todos los objetos se asignen en el montón. Mediante técnicas de análisis de escape, los objetos pueden asignarse en la pila, lo que puede reducir el GC y mejorar el rendimiento del programa.

Pero, ¿el rendimiento del programa con el análisis de escape activado es necesariamente mayor que el rendimiento del programa sin el análisis de escape activado? No necesariamente. La tecnología de análisis de escape es en realidad muy complicada, por lo que también es un proceso que requiere mucho tiempo. Si se descubre que todos los objetos se han escapado después del análisis de escape, no se puede realizar la optimización y el proceso de análisis de escape consumirá tiempo. de optimización, la ganancia supera la pérdida.

Supongo que te gusta

Origin blog.csdn.net/Trouvailless/article/details/124450256
Recomendado
Clasificación