descargar - update java windows
¿La verificación del código de bytes ocurre dos veces? (5)
No hay tal verificación de dos veces
NO , en lo que respecta a la verificación, observe detenidamente cómo el programa escrito en java atraviesa varias fases en la siguiente imagen. Verá que no hay tal verificación de dos veces, pero el código se verifica solo una vez.
- EDITAR - El programador escribe el programa (preferiblemente en un bloc de notas) y lo guarda como un archivo ''.java'', que el compilador luego utiliza para compilación.
COMPILAR - El compilador aquí toma el archivo ''.java'', lo compila y busca posibles errores en el alcance del programa. Si encuentra algún error, se lo informa al programador. Si no hay ningún error, el programa se convierte en bytecode y se guarda como un archivo ''.class''.
CARGAR - Ahora, el principal objetivo del componente llamado ''Class Loader'' es cargar el código de bytes en la JVM. Aún no ejecuta el código, solo lo carga en la memoria de la JVM.
VERIFICAR : después de cargar el código, la subparte de la JVM llamada ''Verte Code Byte'' verifica el código de byte y lo verifica por su autenticidad. También verifica si el bytecode tiene algún código que pueda conducir a algún resultado malicioso. Este componente de la JVM garantiza la seguridad.
EJECUTAR : el siguiente componente es el motor de ejecución. El motor de ejecución interpreta el código línea por línea utilizando el compilador Just In Time (JIT). El compilador JIT hace la ejecución bastante rápido pero consume memoria caché extra.
Esta pregunta ya tiene una respuesta aquí:
- ¿Cómo se verifica el bytecode en la JVM? 2 respuestas
Así que estoy un poco confundido con respecto a la verificación del código de bytes que ocurre dentro de una JVM. Según el libro de Deitel y Deitel , un programa Java pasa por cinco fases (editar, compilar, cargar, verificar y ejecutar) (capítulo 1). El verificador de código de bytes verifica el bytecode durante la etapa ''verificar''. En ninguna parte el libro menciona que el verificador de bytecode es una parte del cargador de clases.
Sin embargo, de acuerdo con los documentos de Oracle , el cargador de clases realiza la tarea de cargar, vincular e inicializar, y durante el proceso de vinculación debe verificar el código de bytes.
Ahora, ¿la verificación de bytecode de la que hablan Deitel y Deitel, y la verificación de bytecode de la que habla este documento de Oracle, el mismo proceso?
¿O la verificación del código de bytes ocurre dos veces, una vez durante el proceso de enlace y la otra mediante el verificador de código de bytes?
Imagen que describe las fases de un programa java como se menciona en el libro de Dietel y Dietel. (Tomé prestada esta foto de una de las siguientes respuestas de nobalG :))
La especificación enumera 4 fases en la verificación de código de bytes. Estos pasos son funcionalmente distintos, para no confundirse con repetir lo mismo. Al igual que un compilador de múltiples pases usa cada paso para la configuración del siguiente paso, las fases no son repeticiones, sino que se organizan para un solo propósito general, cada fase realiza ciertas tareas.
A menos que se cambie el bytecode, no hay razón para verificarlo dos veces.
La verificación se describe aquí.
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10
La verificación del código ocurre dos veces . Una vez durante la compilación (la compilación falla si el código tiene fallas, amenazas) y nuevamente una vez que la clase se carga en la memoria durante la ejecución (aquí se realiza la verificación del código de bytes real). Sí, esto sucede junto con el proceso de carga de clases (por cargadores de clase) , pero los cargadores de clase en sí mismos podrían no actuar como verificadores. Es la JVM (o más bien el verificador presente en la JVM) que hace la verificación.
No.
De la especificación JVM 4.10 :
Aunque un compilador para el lenguaje de programación Java solo debe producir archivos de clase que satisfagan todas las restricciones estáticas y estructurales en las secciones anteriores, la Máquina Virtual Java no garantiza que el compilador genere ningún archivo que se le solicite o que esté correctamente formado.
Y luego procede a especificar el proceso de verificación.
Y JVM Spec 5.4.1 :
La verificación (§4.10) garantiza que la representación binaria de una clase o interfaz sea estructuralmente correcta (§4.9). La verificación puede ocasionar que se carguen clases e interfaces adicionales (§5.3) pero no es necesario que sean verificadas o preparadas.
La sección que especifica el enlace de las referencias §4.10 - no como un proceso separado sino como parte de la carga de las clases.
JVM y JLS son excelentes documentos cuando tienes una pregunta como esta.
Puede comprender la verificación del código byte usando este diagrama que se explica detalladamente en la documentación de Oracle
Encontrará que la verificación del código de byte ocurre solo una vez, no dos veces
La ilustración muestra el flujo de datos y control desde el código fuente del lenguaje Java a través del compilador de Java, al cargador de clases y al verificador de código de bytes y, por lo tanto, a la máquina virtual de Java, que contiene el intérprete y el sistema de tiempo de ejecución. El problema importante es que el cargador de clases de Java y el verificador de bytecode no hacen suposiciones acerca de la fuente principal del flujo de bytecode; el código puede provenir del sistema local o puede haber viajado por la mitad del planeta. El verificador de bytecode actúa como una especie de controlador de acceso: garantiza que el código que se pasa al intérprete de Java se encuentre en un estado adecuado para ejecutarse y pueda ejecutarse sin temor a romper el intérprete de Java. El código importado no puede ejecutarse por ningún medio hasta que haya pasado las pruebas del verificador. Una vez que se realiza el verificador, se conocen una serie de propiedades importantes:
- No hay desbordamientos o subflujos en la pila de operandos
- Se sabe que los tipos de parámetros de todas las instrucciones de bytecode son siempre correctos
- Los accesos a campos de objetos son legales, privados, públicos o protegidos.
Si bien todas estas comprobaciones parecen extremadamente detalladas, para cuando el verificador de bytecode haya realizado su trabajo, el intérprete de Java puede continuar, sabiendo que el código se ejecutará de forma segura. Conocer estas propiedades hace que el intérprete de Java sea mucho más rápido, ya que no tiene que verificar nada. No hay comprobaciones de tipo de operandos ni comprobaciones de desbordamiento de pila. El intérprete puede funcionar a toda velocidad sin comprometer la fiabilidad.
EDITAR:-
De la sección 5.3.2 de Oracle Docs:
Cuando se invoca el método loadClass del cargador de clases L con el nombre N de una clase o interfaz C para cargar, L debe realizar una de las dos operaciones siguientes para cargar C:
- El cargador de clases L puede crear una matriz de bytes que representan C como los bytes de una estructura de ClassFile (§4.1); luego debe invocar el método defineClass de la clase ClassLoader. Invocar defineClass hace que la Máquina Virtual de Java derive una clase o interfaz denotada por N usando L de la matriz de bytes usando el algoritmo que se encuentra en §5.3.5.
- El cargador de clases L puede delegar la carga de C a otro cargador de clases L ''. Esto se logra pasando el argumento N directa o indirectamente a una invocación de un método en L ''(generalmente el método loadClass). El resultado de la invocación es C.
Como lo comentó Holger correctamente, tratando de explicarlo más con la ayuda de un example :
static int factorial(int n)
{
int res;
for (res = 1; n > 0; n--) res = res * n;
return res;
}
El código byte correspondiente sería
method static int factorial(int), 2 registers, 2 stack slots
0: iconst_1 // push the integer constant 1
1: istore_1 // store it in register 1 (the res variable)
2: iload_0 // push register 0 (the n parameter)
3: ifle 14 // if negative or null, go to PC 14
6: iload_1 // push register 1 (res)
7: iload_0 // push register 0 (n)
8: imul // multiply the two integers at top of stack
9: istore_1 // pop result and store it in register 1
10: iinc 0, -1 // decrement register 0 (n) by 1
11: goto 2 // go to PC 2
14: iload_1 // load register 1 (res)
15: ireturn // return its value to caller
Tenga en cuenta que la mayoría de las instrucciones en JVM están escritas.
Ahora debe tener en cuenta que el funcionamiento correcto de la JVM no está garantizado a menos que el código cumpla al menos las siguientes condiciones:
- Tipo de corrección: los argumentos de una instrucción son siempre de los tipos esperados por la instrucción.
- Sin acumulación de flujo o subdesbordamiento: una instrucción nunca muestra un argumento de una pila vacía, ni empuja un resultado en una pila completa (cuyo tamaño es igual al tamaño máximo de pila declarado para el método).
- Contención del código: el contador del programa siempre debe apuntar dentro del código para el método, al comienzo de una codificación de instrucción válida (sin caer al final del código del método, sin ramas en el medio de una codificación de instrucción).
- Inicialización del registro: una carga de un registro siempre debe seguir al menos una tienda en este registro; en otros términos, los registros que no corresponden a los parámetros del método no se inicializan en la entrada del método, y es un error cargar desde un registro sin inicializar.
- Inicialización de objetos: cuando se crea una instancia de una clase C, se debe invocar uno de los métodos de inicialización para la clase C (que corresponde a los constructores de esta clase) antes de poder usar la instancia de la clase.
El propósito de la verificación del código de bytes es verificar estas condiciones de una vez por todas , mediante el análisis estático del código de bytes en el momento de la carga. El código de bytes que pasa la verificación se puede ejecutar más rápido.
También tenga en cuenta que el propósito de la verificación del código de bytes es cambiar la verificación anterior del tiempo de ejecución al tiempo de carga.
La explicación anterior ha sido tomada de example