Pourquoi Java 8 lambdas appelée à l'aide de invokedynamic?
La invokedynamic
instruction est utilisé pour aider à la VM de déterminer la méthode de référence au moment de l'exécution au lieu de brancher au moment de la compilation.
C'est utile avec des langages dynamiques où la méthode exacte et les types d'argument ne sont pas connus jusqu'à l'exécution. Mais ce n'est pas le cas avec les lambdas de Java. Ils sont convertis en statique méthode bien définie arguments. Et cette méthode peut être appelée à l'aide de invokestatic
.
Alors, quelle est la nécessité de invokedynamic
pour les lambdas, surtout quand il y a un gain de performance?
- Brian Goetz l'explique ici: wiki.jvmlangsummit.com/images/1/1e/2011_Goetz_Lambda.pdf
invokedynamic
est pas utilisé pour appeler lambda, mais pour créer et lier un MethodHandle pour lambda du corps au site d'appel.- Indy est utilisée pour capturer l'lambda, pas l'invoquer.
- Nous utilisons
invokedynamic
parce qu'il fournit à une amélioration de la performance, pas de dégradation des performances, sur le "évident" de la traduction des schémas. (Je ne sais pas d'où vous est venue l'idée qu'il y aurait un gain de performance, mais c'est incorrect.) - Il y a de test de performance stackoverflow.com/questions/19001241/...: "La ligne de fond est que le post compilation JIT, lambdas et anonyme classes effectuent de la même manière sur l'actuel Hostpot JVM implémentations".
- les lambdas ne sont pas traduits à des méthodes statiques.
- De référence?
Vous devez vous connecter pour publier un commentaire.
Lambdas ne sont pas appelés à l'aide
invokedynamic
, leur représentation d'objet est créé à l'aide deinvokedynamic
, le réel de l'invocation est un régulierinvokevirtual
ouinvokeinterface
.Par exemple:
Tout lambda est de devenir une instance de base de la classe ou de l'interface. Cette instance sera parfois contenir une copie des variables capturées à partir de la méthode originale et parfois un pointeur vers l'objet parent.
Cela peut être mis en œuvre comme une classe anonyme.
Pourquoi invokedynamic
La réponse courte est: pour générer du code à l'exécution.
Les responsables Java choisi de générer la mise en œuvre de la classe runtime.
Ceci est fait en appelant
java.lang.invoke.LambdaMetafactory.metafactory
.Puisque les arguments pour cet appel (type de retour, de l'interface et les paramètres capturés) peut changer, cela nécessite
invokedynamic
.À l'aide de
invokedynamic
pour construire la classe anonyme dans l'exécution, permet à la JVM pour générer du bytecode de la classe runtime. Les appels suivants à la même déclaration utiliser une version mise en cache. L'autre raison d'utiliserinvokedynamic
est d'être en mesure de modifier la stratégie de mise en œuvre dans l'avenir sans avoir à modifier le code compilé.La route pas pris
L'autre option serait le compilateur de la création d'un innerclass pour chaque lambda instanciation, l'équivalent de traduire le code ci-dessus dans:
Cela nécessite la création de classes dans les temps de compilation et d'avoir à charge au cours de l'exécution. Le chemin de la jvm des œuvres de ces classes de résider dans le même répertoire que la classe d'origine. Et la première fois que vous exécutez l'instruction qui utilise que les lambda, que la classe anonyme devrait être chargé et initialisé.
Sur les performances
Le premier appel à
invokedynamic
de déclencher la classe anonyme génération. Puis l'opcodeinvokedynamic
est remplacé par code que du rendement équivalent à l'écriture manuelle de la anonyme de l'instanciation.invokedynamic
va générer plus de déchets ...” ou que l'exécution répétée de la mêmeinvokedynamic
instruction crée aucun poubelle?java.lang.invoke.MethodHandles.findStatic
.java.lang.invoke
cadre, qui ne sont pas liés à votre expression lambda à tous. L'étape jusqu'à ce quei==1
et de voir combien de fois votre point d'arrêt sera frappé puis.MethodHandle.invokeExact
prend un Objet[] comme paramètre.invokedynamic
instruction. Si vous placez une expression lambda avant de la boucle et de vérifier ensuite, vous verrez que leinvokedynamic
instruction dans la boucle d'appelfindStatic
exactement une seule fois lors de couplage sur la première invocation. Cela s'applique à tous les autres par la suite exécutéinvokedynamic
instructions ainsi, et c'est indiqué qu'après avoir terminé le couplage de la dynamique callsite, il restera lié à jamais. Et la méthode se charge de faire pas prendreObject[]
comme paramètre.invokeExact
prend un Objet[] comme paramètre.java.lang.invoke
: Chaque appel dynamique du site des transitions plus d'une fois de liés à liés, juste avant sa première invocation. Il n'y a aucun moyen d'annuler l'effet d'un appel à la méthode du bootstrap. Et essayer de comprendre Signature de polymorphisme avant de discuter plus loin...Cerveau Goetz a expliqué les raisons pour le lambda stratégie de traduction dans l'une de ses papiers qui, malheureusement, semblent désormais indisponible. Heureusement j'ai gardé une copie:
Donc, l'idée semble être de résumer la stratégie de la traduction et de ne pas s'engager à une façon particulière de faire les choses à cacher les détails. Dans l'avenir, lorsque le type de l'effacement et de l'absence de types de valeur ont été résolus et peut-être Java prend en charge la fonction de types, ils pourraient tout aussi bien y aller et modifier la stratégie pour un autre, sans causer de problèmes dans le code.
Actuelle de Java 8 lambda mise en œuvre est un composé de décision:
Donc, pour répondre à votre question,