Existe-t-il des fonctions en ligne dans Java?


112

Existe-t-il un concept de fonctions en ligne en java, ou est-il remplacé par quelque chose d'autre? S'il y en a, comment est-il utilisé? J'ai entendu cela public, staticet les finalméthodes sont les fonctions en ligne. Pouvons-nous créer notre propre fonction en ligne?


4
Juste pour clarifier, vous voulez dire en.wikipedia.org/wiki/Inline_function , pas en.wikipedia.org/wiki/Anonymous_function , n'est-ce pas?
JW.

3
À titre de commentaire mineur, l'optimisation prématurée est la racine de tout mal. Si vous ne comprenez pas pleinement la nature du public, du statique et du final, vous ne pouvez pas vraiment comprendre l'impact que pourrait avoir l'inlining - et cela dépend de la JVM que vous utilisez. Assurez-vous d'abord de répondre aux raisons pour lesquelles vous devez intégrer quelque chose: il est presque certain que vous pouvez faire des optimisations de retour sur investissement plus élevées ailleurs.
Nathaniel Ford

Réponses:


123

En Java, les optimisations sont généralement effectuées au niveau JVM. Au moment de l'exécution, la JVM effectue une analyse «compliquée» pour déterminer les méthodes à intégrer. Il peut être agressif en inlining, et la JVM Hotspot peut en fait intégrer des méthodes non finales.

Les compilateurs java n'intègrent presque jamais aucun appel de méthode (la JVM fait tout cela à l'exécution). Ils compilent en ligne les constantes de temps (par exemple, les valeurs primitives statiques finales). Mais pas de méthodes.

Pour plus de ressources:

  1. Article: Le moteur de performance Java HotSpot: exemple d'inclusion de méthode

  2. Wiki: Inlining dans OpenJDK , pas entièrement rempli mais contient des liens vers des discussions utiles.


15

Non, il n'y a pas de fonction en ligne dans java. Oui, vous pouvez utiliser une méthode statique publique n'importe où dans le code lorsqu'elle est placée dans une classe publique. Le compilateur java peut faire une expansion en ligne sur une méthode statique ou finale, mais ce n'est pas garanti.

En général, de telles optimisations de code sont effectuées par le compilateur en combinaison avec JVM / JIT / HotSpot pour les segments de code très souvent utilisés. De plus, d'autres concepts d'optimisation comme la déclaration de paramètres de registre ne sont pas connus en java.

Les optimisations ne peuvent pas être forcées par déclaration en java, mais effectuées par le compilateur et JIT. Dans de nombreux autres langages, ces déclarations ne sont souvent que des indices du compilateur (vous pouvez déclarer plus de paramètres de registre que le processeur n'en a, le reste est ignoré).

Déclarer des méthodes java statiques, finales ou privées sont également des conseils pour le compilateur. Vous devriez l'utiliser, mais aucune garantie. Les performances Java sont dynamiques et non statiques. Le premier appel à un système est toujours lent à cause du chargement de classe. Les appels suivants sont plus rapides, mais en fonction de la mémoire et de l'exécution, les appels les plus courants sont optimisés dans le système en cours d'exécution, de sorte qu'un serveur peut devenir plus rapide pendant l'exécution!


3
finalne pas avoir d'impact sur l'inlining JIT
Steve Kuo

1
+1, mais comment tester si la version compilée d'une méthode est incorporée?
Pacerier

@Pacerier Mais pourquoi devrions-nous tester si quelque chose est en ligne?
Arne Burmeister le

14

Java ne permet pas de suggérer manuellement qu'une méthode doit être intégrée. Comme le dit @notnoop dans les commentaires, l'inlining est généralement effectué par la JVM au moment de l'exécution.


3
La plupart des compilateurs java ne font jamais d'appels de méthode en ligne. C'est principalement la JVM qui le fait.
notnoop

Merci d'avoir clarifié cela. Je ne savais pas exactement dans quelle phase cela s'était passé. Je vais modifier mon message pour refléter cela.
Thomas Owens

@ThomasOwens c'est le cas, mais ce n'est pas publicjdk.internal.vm.annotation.ForceInline
Eugene

4

Ce que vous avez dit ci-dessus est correct. Parfois, les méthodes finales sont créées en ligne, mais il n'y a pas d'autre moyen de créer explicitement une fonction en ligne en java.


5
Les méthodes finales ne sont pas garanties en ligne.
Thomas Owens

4
Sur HotSpot, l'ajout finalne fait même aucune différence quant à savoir si la méthode est intégrée ou non.
Tom Hawtin - tackline

4
@Thomas - c'est pourquoi j'ai dit "Parfois les méthodes finales ..."
GreenieMeanie

@ TomHawtin-tackline avez-vous une source faisant autorité pour cela? Pour autant que je sache, les méthodes finales peuvent être incorporées sans utiliser de garde de type, ce qui signifie que le modificateur rend l'intégration de la méthode plus efficace que sans le modificateur. Je sais que Jikes RVM en tient compte au moment de décider s'il faut en ligne. Êtes-vous certain que HotSpot ne fait pas quelque chose de similaire?
Jannik Jochem

2

Exemple réel:

public class Control {
    public static final long EXPIRED_ON = 1386082988202l;
    public static final boolean isExpired() {
        return (System.currentTimeMillis() > EXPIRED_ON);
    }
}

Ensuite, dans d'autres classes, je peux quitter si le code a expiré. Si je référence la variable EXPIRED_ON d'une autre classe, la constante est en ligne avec le code d'octet, ce qui rend très difficile la localisation de tous les endroits dans le code qui vérifie la date d'expiration. Cependant, si les autres classes invoquent la méthode isExpired (), la méthode réelle est appelée, ce qui signifie qu'un pirate peut remplacer la méthode isExpired par une autre qui renvoie toujours false.

Je suis d'accord que ce serait très bien de forcer un compilateur à intégrer la méthode statique finale à toutes les classes qui la référencent. Dans ce cas, vous n'avez même pas besoin d'inclure la classe Control, car elle ne serait pas nécessaire au moment de l'exécution.

D'après mes recherches, cela ne peut pas être fait. Peut-être que certains outils d'Obfuscator peuvent le faire, ou vous pouvez modifier votre processus de construction pour éditer les sources avant la compilation.

Pour prouver si la méthode de la classe de contrôle est placée en ligne dans une autre classe lors de la compilation, essayez d'exécuter l'autre classe sans la classe Control dans le chemin de classe.


2

Eh bien, il existe des méthodes qui peuvent être appelées méthodes "en ligne" en java, mais en fonction du jvm. Après la compilation, si le code machine de la méthode est inférieur à 35 octets, il sera immédiatement transféré vers une méthode en ligne, si le code machine de la méthode est inférieur à 325 octets, il pourrait être transféré dans une méthode en ligne, en fonction du jvm.


1
Ce sont les valeurs par défaut pour la VM d'Oracle, voir docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
rmuller

0

donc, il semble qu'il n'y en ait pas, mais vous pouvez utiliser cette solution de contournement en utilisant la goyave ou une implémentation de classe Function équivalente, car cette classe est extrêmement simple, par exemple:

    assert false : new com.google.common.base.Function<Void,String>(){
        @Override public String apply(Void input) {
            //your complex code go here
            return "weird message";
        }}.apply(null);

oui, c'est du code mort juste pour illustrer comment créer un bloc de code complexe (dans {}) pour faire quelque chose de si spécifique qui ne devrait pas nous déranger pour créer une méthode pour cela, AKA en ligne!


Cela semble être une idée raisonnable. En avez-vous une version qui n'utilise pas les bibliothèques communes de Google?
ragerdl

0

Java9 a un compilateur "Ahead of time" qui effectue plusieurs optimisations au moment de la compilation, plutôt que lors de l'exécution, ce qui peut être considéré comme une intégration.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.