2011-08-16 3 views
7

Un working document décrivant l'état de Project Lambda mentionne les types SAM (méthode abstraite unique). Autant que je sache, la proposition lambda actuelle n'affecte pas l'exécution juste le compilateur en rendant possible la conversion automatique des expressions lambda à ces types.Java - Optimisation de type SAM

Je pense que dans des circonstances idéales, les instances de types SAM pourraient être représentées en interne par des pointeurs de fonction. Par conséquent, la machine virtuelle Java peut éviter l'allocation de mémoire pour ces instances.

Je me demande si les machines virtuelles modernes sont capables de fournir une telle optimisation.

+0

Lorsque vous dites "pointeur de fonction", voulez-vous dire pointeur simple au début du code de fonction? – ffriend

+0

@ffriend - Oui, je le fais.Je sais qu'il y a quelques problèmes avec cette approche, par exemple il est possible de synchroniser sur un objet. Mais la JVM peut également effectuer d'autres optimisations non triviales, par exemple en insérant des méthodes virtuelles. –

Répondre

6

@ Tamás Vous devriez avoir lu cette liste mailing poste Brian Goetz:

http://mail.openjdk.java.net/pipermail/lambda-dev/2011-August/003877.html

Fondamentalement, abstraction lambda actuellement implémenté utilisant objets. Cependant, il a été conçu pour permettre des réalisations alternatives de lambdas, qui seraient "plus petites" que les instances de classes.

Vous pouvez considérer la situation comme similaire à l'autoboxing - les entiers sont encadrés dans Integer, mais ont une représentation "plus petite" (comme ints).

Actuellement, lambdas doit être encadré à des instances de types SAM, b/c la JVM n'a actuellement aucun moyen de représenter un lambda avec une construction plus petite. À l'avenir, il pourrait y avoir une nouvelle norme JVM qui inclurait des «fonctions primitives» qui pourraient représenter les lambdas autrement que comme des objets. Donc, pour répondre à votre question, le type d'optimisation que vous proposez ci-dessus est peut-être possible, mais cela viendrait probablement du travail post-Java 8 sur les «fonctions primitives» plutôt que sur une fonctionnalité spécifique à l'implémentation.

5

Il n'y a rien de difficile à convertir des classes de méthode unique en pointeurs de fonction, mais il vous manque une chose: les expressions lambda ne sont pas simplement des fonctions, elles sont fermetures. La différence est que les fermetures peuvent capturer des variables externes. Considérons par exemple suivant en pseudo Java:

public Adder makeAdder(double startNumber) { 
    return #{ int number -> number + startNumber} 
} 

... 

int startNumber = 5; 
Adder add5 = makeAdder(startNumber); 
add5.invoke(4); // ==> 9 

Dans cet exemple, la fonction lambda, produite par l'appel à makeAdder(), fait référence à la variable qui a été définie en dehors de ce lambda. C'est pourquoi on l'appelle "fermetures" - elles sont "fermées" sur leurs variables libres (dans ce cas - sur startNumber). Pour gérer de telles situations, les fermetures doivent contenir à la fois un pointeur vers une fonction et un pointeur vers son environnement . Donc, vous obtenez une structure de données qui a une méthode et au moins une variable. Mais n'est-ce pas une définition d'un objet dans OOP? Alors, quelle est la raison de créer un nouveau type d'objets si vous pouvez en faire une instance de classe anonyme?

Néanmoins, d'autres optimisations sur de telles classes anonymes peuvent être effectuées. Le document de travail que vous avez pointé mentionne certains d'entre eux, par exemple, déduire et utiliser efficacement les variables finales (bien que cela soit fait principalement pour permettre à lambdas sur JVM en principe, d'optimiser le code). Les classes anonymes produites peuvent aussi être finalisées, et la plupart des JVM ont déjà de bonnes optimisations pour les classes et les vars finaux.

D'autres améliorations peuvent également concerner des références à l'environnement - il y a des tonnes d'options là.

+0

Merci pour la réponse! La seule chose qui m'inquiète est l'allocation de mémoire pour ces objets, ce qui peut limiter la concurrence, puisque pour autant que je sache, chaque allocation de mémoire implique un certain nombre de synchronisations. Bien sûr je sais que la gestion des objets réutilisables est la responsabilité du programmeur, je voulais juste savoir si la JVM est capable d'éviter l'allocation de mémoire pour ces objets. –

+1

@ Tamás: pouvez-vous s'il vous plaît pointer vers les ressources sur la synchronisation lors de l'allocation de la mémoire? Je ne trouve aucune information sur ce sujet, mais je crois que l'allocation de mémoire par défaut dans JVM n'utilise pas des choses comme 'synchronized': l'allocation à un seul thread dans les VM modernes nécessite seulement une assignation à la référence et un incrément de pointeur. Je crois que la sécurité des threads dans l'allocation de mémoire multithread est faite par des constructions de très bas niveau, éventuellement basées sur des opérations atomiques du processeur, et donc très rapides aussi. Si tel est le cas, il n'y a pas de problème à se soucier de la synchronisation lors de la création de la fermeture. – ffriend

+3

@ Tamás Hotspot utilise les tampons TLS (stockage local) en interne et uniquement si ceux-ci sont alloués globalement sur le tas global, ce qui peut entraîner une surcharge de synchronisation, mais n'est pas très coûteux - c'est juste un incrément de pointeur Je ne sais pas mais c'est presque certainement implémenté avec une boucle CAS). – Voo