30 votes

La vérification du code d'octet se produit-elle deux fois?

Alors je suis un peu confus en ce qui concerne la vérification de bytecode qui se passe à l'intérieur d'une JVM. Selon le livre de Deitel et Deitel, un programme Java passe par cinq phases (éditer, compiler, de charger, de les vérifier et de les exécuter) (chapitre 1). Le bytecode verifier vérifie le bytecode lors de la 'vérifier' étape. Nulle part dans le livre de mentionner que le bytecode verifier est une partie du chargeur de classe.

Cependant, selon docs de l'oracle le chargeur de classe effectue la tâche de chargement, de liaison et de l'initialisation, et pendant le processus de liaison dont il dispose pour vérifier le bytecode.

Maintenant, est-ce le pseudo-code de vérification que Deitel et Deitel en parle, et le pseudo-code de vérification que ce document oracle parle, le même processus?

Ou ne bytecode vérification arriver deux fois, une fois pendant le processus de liaison et de l'autre par le bytecode verifier?

Photo décrivant les étapes d'un programme java comme mentionné dans le livre de Dietel et Dietel.(J'ai emprunté cette photo à partir de l'une des réponses ci-dessous par nobalG :) ) enter image description here

21voto

Rahul Tripathi Points 1

Vous pouvez comprendre que le byte code de vérification à l'aide de ce diagramme, qui est détaillée dans Oracle docs

enter image description here

Vous trouverez que le byte code de vérification n'arrive qu'une fois et pas deux

L'illustration montre le flux de données et de contrôle du langage Java code source par le compilateur Java, le chargeur de classe et bytecode verifier et, partant, sur la machine virtuelle Java, qui contient l'interprète et le système d'exécution. La question importante est de que la classe Java chargeur et le bytecode verifier font pas de hypothèses sur la source primaire du bytecode stream--le code peut venir à partir du système local, ou il peut avoir traversé la moitié autour de la planète. Le bytecode verifier agit comme une sorte de gardien: il garantit que le code transmis à l'interprète de Java est dans un état d'être exécuté, et peut s'exécuter sans crainte d'enfreindre la Java interprète. Importées de code n'est pas autorisé à exécuter par tous les moyens jusqu'à ce que après qu'il a passé le vérificateur de tests. Une fois que le vérificateur est fait, un certain nombre de propriétés importantes sont connus:

  • Il n'y a pas d'opérande débordements de pile ou underflows
  • Les types des paramètres de toutes les instructions bytecode sont connus pour toujours être correctes
  • Champ d'objet accède sont connus pour être légal--privé, public ou protégé

Alors que tous ce contrôle apparaît extrêmement détaillée, par le temps le bytecode verifier a fait son œuvre, l'interprète de Java peut procéder, sachant que le code va s'exécuter en toute sécurité. Sachant que ces propriétés en fait l'interprète de Java beaucoup plus rapide, car il n'a pas vérifier quoi que ce soit. Il n'y a pas d'opérande type de contrôles et aucune pile débordement de contrôles. L'interprète peut ainsi fonctionner à pleine vitesse sans compromettre la fiabilité.

EDIT:-

À Partir D'Oracle Docs Section 5.3.2:

Lorsque la méthode loadClass de la classe loader L est appelé avec l' nom N d'une classe ou d'interface C pour être chargé, L doit effectuer l'une des les deux opérations suivantes dans l'ordre de charger C:

  • Le chargeur de classe L peut créer un tableau d'octets qui représentent C comme les octets d'un ClassFile structure (§4.1); ensuite, elle doit appeler le méthode defineClass de la classe ClassLoader. Invoquant defineClass les causes de la Machine Virtuelle Java pour dériver une classe ou une interface dénoté par N à l'aide de L dans le tableau d'octets à l'aide de l'algorithme au §5.3.5.
  • Le chargeur de classe L peut déléguer le chargement de C pour la classe loader L'. Ceci est accompli en passant l'argument N directement ou indirectement à l'invocation d'une méthode sur L' (en général, la méthode loadClass). Le résultat de l'invocation est C.

Comme correctement commenté par Holger, en essayant d'expliquer qu'il est plus avec l'aide d'un exemple:

static int factorial(int n)
{
int res;
for (res = 1; n > 0; n--) res = res * n;
return res;
}

L'octet correspondant de code serait

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

Notez que la plupart des instructions de la JVM sont tapés.

Maintenant, vous devez noter que le bon fonctionnement de la JVM n'est pas garantie, sauf si le code se réunit au moins les conditions suivantes:

  • Type de justesse: les arguments de l'un à l'instruction sont toujours de la types attendus par l'instruction.
  • Pas de débordement de pile ou de dépassement de capacité: une instruction de ne jamais pop un argument hors une pile vide, ni pousse un résultat sur une pile complète (dont la taille est égale à la durée maximale de la pile de la taille déclarée pour la méthode).
  • Code de confinement: le compteur de programme doivent toujours au sein de la code de la méthode, le début d'un permis de codage d'instruction (pas de tomber de la fin de la code de la méthode; pas de branches dans la milieu d'une instruction de codage).
  • Registre d'initialisation: une charge à partir d'un registre doit toujours suivi moins d'un magasin dans ce registre; en d'autres termes, les registres qui ne correspondent pas aux paramètres de la méthode ne sont pas initialisés sur la méthode d'entrée, et c'est une erreur de les charger à partir d'un non initialisée registre.
  • L'initialisation de l'objet: lorsqu'une instance d'une classe C est créé, un des méthodes d'initialisation pour la classe C (correspondant à la les constructeurs de cette classe) doit être appelé avant la classe instance peut être utilisée.

Le but de byte code de vérification consiste à vérifier ces conditions une fois pour toutes, par l'analyse statique de code octet au moment du chargement. Byte code qui passe verfification peut ensuite être exécuté plus rapidement.

Également de noter que la vérification du code octet but est de changer la verfification énumérés ci-dessus à partir de l'exécution pour les temps de chargement.

L'explication ci-dessus a été prise à partir de bytecode Java vérification: algorithmes et formalizations

9voto

jdphenix Points 2349

Pas de.

À partir de la JVM Spec 4.10:

Même si un compilateur pour le langage de programmation Java doit seulement de produire des fichiers de classe qui répondent à tous les statiques et les contraintes structurelles dans les sections précédentes, la Machine Virtuelle Java n'a pas de garantie que n'importe quel fichier il est demandé à charge a été généré par le compilateur ou est correctement formé.

Et procède ensuite spécifier le processus de vérification.

Et JVM Spec 5.4.1:

De vérification (§4.10) veille à ce que la représentation binaire d'une classe ou d'interface est structurellement correct (§4.9). La vérification peut entraîner d'autres classes et interfaces chargées (§5.3), mais n'a pas besoin de les amener à être vérifié ou de la préparation.

La section spécification de liaison des références §4.10 - non pas comme un processus distinct, mais une partie de chargement de classes.

La JVM et JLS sont de grands documents lorsque vous avez une question comme ça.

9voto

nobalG Points 2289

Aucun de ces Deux temps de la vérification

PASautant Que la vérification porte,regardez attentivement ce que la façon dont le programme écrit en java passe par différentes phases dans l'image suivante,Vous verrez qu'il n'y est aucune de ces Deux temps de la vérification , mais le code est vérifié qu'une seule fois.

enter image description here

  • MODIFIEZ – Le programmeur écrit le programme (de préférence sur un bloc-notes) et l'enregistre comme une ‘.java', qui est ensuite utilisée pour la compilation, le compilateur.
  • COMPILEZ – Le compilateur prend ici le".java fichier, compile et recherche les erreurs éventuelles dans le cadre du programme. Si il trouve toute erreur, elle le signale au programmeur. Si aucune erreur n' est-il, alors le programme est convertie en bytecode et enregistré comme un".la classe de fichier.

  • CHARGE – Maintenant, le but principal de la composante "Class Loader' est à la charge de l'octet de code dans la JVM. Il n'exécute pas le code encore, mais juste de la charge dans la mémoire de la JVM.

  • VÉRIFIEZ – Après le chargement du code, la JVM de la sous-partie appelé " Octet Code vérificateur' vérifie le pseudo-code et vérifie qu'il pour son l'authenticité. Il vérifie également si le pseudo-code a code qui pourrait conduire à des malveillants résultat. Cette composante de la JVM assure la sécurité.

  • EXÉCUTEZ – Le composant suivant est le Moteur d'Exécution. L'exécution moteur interprète le code ligne par ligne en utilisant le Juste À Temps (JIT) compilateur. Le compilateur JIT l'exécution assez rapide mais consomme supplémentaire de mémoire cache.

5voto

codenheim Points 6836

La spécification des listes de 4 phases de vérification de bytecode. Ces étapes sont fonctionnellement distinctes, à ne pas confondre avec de répéter la même chose. Tout comme un multi-pass compilateur utilise chaque passage à l'installation pour le prochain passage, les phases ne sont pas des répétitions, mais sont orchestrées pour un seul but, chaque phase accomplit certaines tâches.

À moins que le pseudo-code est modifié, il n'y a pas de raison de vérifier deux fois.

La vérification est décrite ici.

http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10

2voto

TheLostMind Points 10813

La vérification du code se produit deux fois . Une fois pendant la compilation (la compilation échoue si le code a des défauts, des menaces) et de nouveau après que la classe est chargée en mémoire pendant l'exécution (la vérification du code d'octet se produit ici). Oui, cela se produit avec le processus de chargement des classes (par les chargeurs de classe) , mais les chargeurs de classe eux-mêmes peuvent ne pas agir comme vérificateurs. C'est la JVM (ou plutôt le vérificateur présent dans la JVM) qui fait la vérification.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X