OVH Cloud OVH Cloud

nouvelles optimisation 1.5

23 réponses
Avatar
Pif
Bonjour, j'ai entendu dire que tout ce qui est Vector, Hashtable, et
autres collection, ainsi que ce que propose le projet Trove allaient
être obsoletes du fait de nouvelles optimisations de compilation de JDK
1.5.0 sur la gestion des primitives dans les structures de données... je
n'arrive pas à trouver de lien sur cela...
quelqu'un peut il confirmer et m'indiquer une page pour en savoir plus ?

merci !

10 réponses

1 2 3
Avatar
Örjan Petersson
Marc Petit-Huguenin writes:
Örjan Petersson wrote:
Le but de "autoboxing/autounboxing" n'est pas de complètement faire
disparaître la différence entre les types primitifs (int, short, ...)
et les références correspondants (Integer, Short, ...), et Hotspot ne
peut pas faire disparaître cette différence.


Je ne suis pas d'accord. Pourquoi est-ce que Hotspot ne pourrait pas
transformer un Integer[] en int[] dans le code natif genere?


Parce que pour HotSpot, notre ArrayList<Integer> est en fait une
ArrayList<Object>, et c'est pareil pour les autres collections.
(La généricité est implémentée comme ça. Sans rentrer dans les details,
l'information de la type d'une class générique est "gommé" (type erasure
en anglais) pendant la compilation et n'existe pas au niveau du JVM)
--
Orjan Petersson, Logcode SARL
The email address in the From: header is valid


Avatar
Marc Petit-Huguenin
Örjan Petersson wrote:
Marc Petit-Huguenin writes:

Örjan Petersson wrote:

Le but de "autoboxing/autounboxing" n'est pas de complètement faire
disparaître la différence entre les types primitifs (int, short, ...)
et les références correspondants (Integer, Short, ...), et Hotspot ne
peut pas faire disparaître cette différence.


Je ne suis pas d'accord. Pourquoi est-ce que Hotspot ne pourrait pas
transformer un Integer[] en int[] dans le code natif genere?



Parce que pour HotSpot, notre ArrayList<Integer> est en fait une
ArrayList<Object>, et c'est pareil pour les autres collections.
(La généricité est implémentée comme ça. Sans rentrer dans les details,
l'information de la type d'une class générique est "gommé" (type erasure
en anglais) pendant la compilation et n'existe pas au niveau du JVM)


Vrai, mais incomplet. Le classfile contient un nouvel attribut nomme
"Signature" qui contient la signature complete d'une class, method ou d'un
field. Ca permet d'etre compatible avec les anciennes JVM et de quand meme
permettre a la JVM de faire les optimisations qui s'imposent.



Avatar
Örjan Petersson
Marc Petit-Huguenin writes:

Örjan Petersson wrote:
Marc Petit-Huguenin writes:

Örjan Petersson wrote:

Le but de "autoboxing/autounboxing" n'est pas de complètement faire
disparaître la différence entre les types primitifs (int, short, ...)
et les références correspondants (Integer, Short, ...), et Hotspot ne
peut pas faire disparaître cette différence.


Je ne suis pas d'accord. Pourquoi est-ce que Hotspot ne pourrait pas
transformer un Integer[] en int[] dans le code natif genere?
Parce que pour HotSpot, notre ArrayList<Integer> est en fait une

ArrayList<Object>, et c'est pareil pour les autres collections.
(La généricité est implémentée comme ça. Sans rentrer dans les details,
l'information de la type d'une class générique est "gommé" (type erasure
en anglais) pendant la compilation et n'existe pas au niveau du JVM)


Vrai, mais incomplet. Le classfile contient un nouvel attribut nomme
"Signature" qui contient la signature complete d'une class, method ou
d'un field. Ca permet d'etre compatible avec les anciennes JVM et de
quand meme permettre a la JVM de faire les optimisations qui
s'imposent.


L'attribut "Signature" ne change rien, il permet de retrouver les
"formal type parameters" utilisés pour la déclaration d'une classe (ou
interface, méthode, ...) mais ne donne rien concernant les "type
arguments" effectivement utilisés. Autrement dit, pour une classe
générique

public class C<E> {
E e;
E get() {return e;}
void set(E v) {e = v;}
}

utilisée dans

public class X {
C<Integer> ci = new C<Integer>();
C<String> cs = new C<String>();
...
}

nous avons les signatures (dans C.class)

C - "<T:Ljava/lang/Object;>Ljava/lang/Object;"
t - "TE"
get - "()TE;"
set - "(TE;)V"

et les descripteurs (aussi dans C.class)

set - "(Ljava/lang/Object;)V"
get - "()Ljava/lang/Object;"

L'utilisation de C par X pour stocker un Integer ou un String ne
change pas le fichier C.class. A cause de l'effacement de types (type
erasure) la classe C travaille toujours avec le type java/lang/Object
au niveau bytecode.
--
Orjan Petersson, Logcode SARL
The email address in the From: header is valid




Avatar
Örjan Petersson
"Örjan Petersson" writes:
nous avons les signatures (dans C.class)

C - "<T:Ljava/lang/Object;>Ljava/lang/Object;"
t - "TE"


remplacer le "t" par un "e":
e - "TE"

--
Orjan Petersson, Logcode SARL
The email address in the From: header is valid

Avatar
Marc Petit-Huguenin
Örjan Petersson wrote:
Marc Petit-Huguenin writes:


Örjan Petersson wrote:

Marc Petit-Huguenin writes:


Örjan Petersson wrote:


Le but de "autoboxing/autounboxing" n'est pas de complètement faire
disparaître la différence entre les types primitifs (int, short, ...)
et les références correspondants (Integer, Short, ...), et Hotspot ne
peut pas faire disparaître cette différence.


Je ne suis pas d'accord. Pourquoi est-ce que Hotspot ne pourrait pas
transformer un Integer[] en int[] dans le code natif genere?


Parce que pour HotSpot, notre ArrayList<Integer> est en fait une
ArrayList<Object>, et c'est pareil pour les autres collections.
(La généricité est implémentée comme ça. Sans rentrer dans les details,
l'information de la type d'une class générique est "gommé" (type erasure
en anglais) pendant la compilation et n'existe pas au niveau du JVM)


Vrai, mais incomplet. Le classfile contient un nouvel attribut nomme
"Signature" qui contient la signature complete d'une class, method ou
d'un field. Ca permet d'etre compatible avec les anciennes JVM et de
quand meme permettre a la JVM de faire les optimisations qui
s'imposent.



L'attribut "Signature" ne change rien, il permet de retrouver les
"formal type parameters" utilisés pour la déclaration d'une classe (ou
interface, méthode, ...) mais ne donne rien concernant les "type
arguments" effectivement utilisés. Autrement dit, pour une classe
générique

public class C<E> {
E e;
E get() {return e;}
void set(E v) {e = v;}
}

utilisée dans

public class X {
C<Integer> ci = new C<Integer>();
C<String> cs = new C<String>();
...
}

nous avons les signatures (dans C.class)

C - "<T:Ljava/lang/Object;>Ljava/lang/Object;"
t - "TE"
get - "()TE;"
set - "(TE;)V"

et les descripteurs (aussi dans C.class)

set - "(Ljava/lang/Object;)V"
get - "()Ljava/lang/Object;"

L'utilisation de C par X pour stocker un Integer ou un String ne
change pas le fichier C.class. A cause de l'effacement de types (type
erasure) la classe C travaille toujours avec le type java/lang/Object
au niveau bytecode.


Ton exemple ne correspond pas du tout a la discussion. Je parle
d'optimisation dans l'utilisation de l'auto(un)boxing avec les Collections,
pas avec une classe generique quelconque. Si on a:

public class X {
List<Integer> ci = new ArrayList<Integer>();
List<String> cs = new ArrayList<String>();
...
}

alors la signature contient bien "Ljava/util/List<Ljava/lang/Integer;>;"

Hotspot a alors *toutes* les informations necessaires, et c'est le sujet de
ce thread, pour transformer le "Object[] elementData" en un "int[]
elementData". Ca n'a rien a voir avec le fait que le type est erase a la
compilation. Les anciennes JVMs utiliseront Object[] elementData, mais une
JVM recente pourra faire cette modification lors de la compilation Hotspot
(et elle en fait bien d'autres, et bien plus tordu que ca).
Le fond du probleme reste que donner comme conseil de ne pas utiliser
l'auto(un)boxing avec les Collections pour des raisons de performance est
stupide, et tient plus du Voodoo que d'un raisonnement logique.





Avatar
Vincent Brabant
Örjan Petersson wrote:

Marc Petit-Huguenin writes:


Örjan Petersson wrote:

Marc Petit-Huguenin writes:


Örjan Petersson wrote:


Le but de "autoboxing/autounboxing" n'est pas de complètement faire
disparaître la différence entre les types primitifs (int, short, ...)
et les références correspondants (Integer, Short, ...), et Hotspot ne
peut pas faire disparaître cette différence.



Je ne suis pas d'accord. Pourquoi est-ce que Hotspot ne pourrait pas
transformer un Integer[] en int[] dans le code natif genere?



Parce que pour HotSpot, notre ArrayList<Integer> est en fait une
ArrayList<Object>, et c'est pareil pour les autres collections.
(La généricité est implémentée comme ça. Sans rentrer dans les details,
l'information de la type d'une class générique est "gommé" (type
erasure
en anglais) pendant la compilation et n'existe pas au niveau du JVM)



Vrai, mais incomplet. Le classfile contient un nouvel attribut nomme
"Signature" qui contient la signature complete d'une class, method ou
d'un field. Ca permet d'etre compatible avec les anciennes JVM et de
quand meme permettre a la JVM de faire les optimisations qui
s'imposent.




L'attribut "Signature" ne change rien, il permet de retrouver les
"formal type parameters" utilisés pour la déclaration d'une classe (ou
interface, méthode, ...) mais ne donne rien concernant les "type
arguments" effectivement utilisés. Autrement dit, pour une classe
générique

public class C<E> {
E e;
E get() {return e;}
void set(E v) {e = v;}
}

utilisée dans

public class X {
C<Integer> ci = new C<Integer>();
C<String> cs = new C<String>();
...
}

nous avons les signatures (dans C.class)

C - "<T:Ljava/lang/Object;>Ljava/lang/Object;"
t - "TE"
get - "()TE;"
set - "(TE;)V"

et les descripteurs (aussi dans C.class)

set - "(Ljava/lang/Object;)V"
get - "()Ljava/lang/Object;"

L'utilisation de C par X pour stocker un Integer ou un String ne
change pas le fichier C.class. A cause de l'effacement de types (type
erasure) la classe C travaille toujours avec le type java/lang/Object
au niveau bytecode.



Ton exemple ne correspond pas du tout a la discussion. Je parle
d'optimisation dans l'utilisation de l'auto(un)boxing avec les
Collections, pas avec une classe generique quelconque. Si on a:

public class X {
List<Integer> ci = new ArrayList<Integer>();
List<String> cs = new ArrayList<String>();
...
}

alors la signature contient bien "Ljava/util/List<Ljava/lang/Integer;>;"

Hotspot a alors *toutes* les informations necessaires, et c'est le sujet
de ce thread, pour transformer le "Object[] elementData" en un "int[]
elementData". Ca n'a rien a voir avec le fait que le type est erase a la
compilation. Les anciennes JVMs utiliseront Object[] elementData, mais
une JVM recente pourra faire cette modification lors de la compilation
Hotspot (et elle en fait bien d'autres, et bien plus tordu que ca).
Le fond du probleme reste que donner comme conseil de ne pas utiliser
l'auto(un)boxing avec les Collections pour des raisons de performance
est stupide, et tient plus du Voodoo que d'un raisonnement logique.


A part le fait qu'un Integer peut être null. Et pas un int.
Que doit il faire alors dans ces cas-là ?

Car rien n'interdit de faire le code suivant:
List<Integer> ci = new ArrayList<Integer>();
ci.add(0,new Integer(5));
ci.add(1,5);
ci.add(2,new Integer());
Integer j = ci.get(1);
int i = ci.get(2); ::<-- Null Pointer Exception

Le compilateur ne peut vraiment pas deviner à l'avance que lorsque tu
utilises des ArrrayList<Integer>, tu ne vas JAMAIS utiliser que des int
et pas des Integer.
--
Vincent Brabant
----------------
http://www.netbeans.org/index_fr.html
http://vbrabant-fr.skynetblogs.be






Avatar
Marc Petit-Huguenin
Vincent Brabant wrote:


Hotspot a alors *toutes* les informations necessaires, et c'est le
sujet de ce thread, pour transformer le "Object[] elementData" en un
"int[] elementData". Ca n'a rien a voir avec le fait que le type est
erase a la compilation. Les anciennes JVMs utiliseront Object[]
elementData, mais une JVM recente pourra faire cette modification lors
de la compilation Hotspot (et elle en fait bien d'autres, et bien plus
tordu que ca).
Le fond du probleme reste que donner comme conseil de ne pas utiliser
l'auto(un)boxing avec les Collections pour des raisons de performance
est stupide, et tient plus du Voodoo que d'un raisonnement logique.



A part le fait qu'un Integer peut être null. Et pas un int.
Que doit il faire alors dans ces cas-là ?

Car rien n'interdit de faire le code suivant:
List<Integer> ci = new ArrayList<Integer>();
ci.add(0,new Integer(5));
ci.add(1,5);
ci.add(2,new Integer());
Integer j = ci.get(1);
int i = ci.get(2); ::<-- Null Pointer Exception

Le compilateur ne peut vraiment pas deviner à l'avance que lorsque tu
utilises des ArrrayList<Integer>, tu ne vas JAMAIS utiliser que des int
et pas des Integer.


Hmmm. Le seul probleme que je vois ici est qu'il n'est pas possible de
representer la notion de null dans un tableau d'intS (je parle du code
equivalent generee par Hotspot, pas du bytecode compile). Une solution
serait d'avoir un bitmap associe au tableau qui conserverait cette notion.
Le code genere par Hotspot pour get et add serait alors equivalent a ca:

void add(int value, boolean _null) {
bitmap[size] = _null;
elementData[size++] = value;
}

int get(int index) {
if (bitmap[index]) {
throw new NullPointerException();
}
return elementData[index];
}

Il y a d'autre solutions suivant le compromis vitesse/memoire desire.


Avatar
ZebX
La netiquette, tu connais ?
Ecrire 12 lignes et reprendre un historique de 110...

Il y a des gens qui ont rédigés des FAQ pour les internautes, c'est pas
pour les clebs :
http://www.usenet-fr.net/fr-chartes/index.html

RTFF ;)


--
ZebX - à pied, je prends de l'angle
GnuPG : 0x7B5E2BCF
Avatar
Örjan Petersson
Le 2/4/2004 Marc Petit-Huguenin writes:
IMO: Hotspot peut (va?) optimiser les collections de primitives
auto-boxed, donc pourquoi se faire du soucis? Au pire quelqu'un fera
les mesures qui s'imposent et creera un bug chez Sun.


Un simple test indique que ce n'est pas le cas:

(ici la version pour JDK 1.5)

public class X {
[...]
private int NUM_VALUES = 5000000;
private int NUM_REPS = 10;
public List<Integer> doListWithIntegers1() {
List<Integer> l = new ArrayList<Integer>();

for (int i = 0; i < NUM_VALUES; i++) {
l.add(i);
}
return l;
}

public int doListWithIntegers2(List<Integer> l) {
int sum = 0;

for (int i = 0; i < NUM_VALUES; i++) {
sum = sum + l.get(i); // sum += l.get(i) gives JVM verif. error
}
return sum;
}

void doit(int type) {
long totalTime = 0;
long s1 = 0;

long startTime = System.currentTimeMillis();;
for (int i = 0; i < NUM_REPS; i++) {
s1 += doListWithIntegers2(doListWithIntegers1());
}

totalTime += (System.currentTimeMillis() - startTime);
System.out.println(s1);
System.out.println("Total time: " + totalTime);
}
}

Chez moi (Win XP Pro, PIV 2.2 GHz), le temps d'exécution est
d'environ 18 s pour JDK1.4.2_02 et JDK1.5beta1 avec
$ java -server -Xmx128M
Les deux versions utilisent à peu près la même quantité de mémoire. Pour
comparer, une version de ArrayList qui utilise un int[] au lieu d'un
Object[] prend environ 4.5 s et 25% de la mémoire.

Je te laisse faire le bug report chez Sun :-)

Et le 6/4/2004 Marc Petit-Huguenin writes:
[...]
... Si on a:

public class X {
List<Integer> ci = new ArrayList<Integer>();
List<String> cs = new ArrayList<String>();
...
}

alors la signature contient bien "Ljava/util/List<Ljava/lang/Integer;>;"



Et si on a

public class X {
public void f() {
List<Integer> ci = new ArrayList<Integer>();
List<String> cs = new ArrayList<String>();
...
}
}

il n'y a pas d'attribut Signature pour ci et cs. Il y a bien l'attribut
LocalVariableTypeTable mais il est purement optionnel et n'est pas présent
par defaut (uniquement avec javac -g pour debug info).

De plus, comment veux tu traiter les cas suivants:

void f1() {
ArrayList<Integer> l1 = new ArrayList<Integer>();
l1.add(287);
List l2 = (List) l1.clone(); // clone is shallow
Integer i1 = l1.get(0);
Integer i2 = (Integer)l2.get(0);
assert(i1 == i2);
}

void f2() {
List<Integer> li = new ArrayList<Integer>();
Integer i = 365;
li.add(0, i);
Integer j = li.get(0);
assert (i == j);
}

void f3() {
List<Integer> li = new ArrayList<Integer>();
List ll = li; // warning
ll.add(new Object());
}

[...]
Le fond du probleme reste que donner comme conseil de ne pas utiliser
l'auto(un)boxing avec les Collections pour des raisons de performance
est stupide, et tient plus du Voodoo que d'un raisonnement logique.


Je préfère de performances correctes aujourd'hui que d'être obligé
d'attendre une optimisation hypothétique de HotSpot...
A part de just penser que HotSpot peut le faire, as-tu quelque chose
un peu plus tangible pour affirmer que HotSpot fait/fera cet optimisation?

--
Orjan Petersson, Logcode SARL
The email address in the From: header is valid

Avatar
Marc Petit-Huguenin
Örjan Petersson wrote:
Le 2/4/2004 Marc Petit-Huguenin writes:

IMO: Hotspot peut (va?) optimiser les collections de primitives
auto-boxed, donc pourquoi se faire du soucis? Au pire quelqu'un fera
les mesures qui s'imposent et creera un bug chez Sun.



Un simple test indique que ce n'est pas le cas:


Oui, je sais. Encore une fois ce que je dis n'est pas "Il faut utiliser
l'autoboxing avec les collections parceque c'est aussi rapide qu'un tableau
de primitives", mais "Dire de ne pas utiliser l'autoboxing avec les
Collections parceque c'est lent est un mauvais conseil".

Regles:

1. Designer le meilleur systeme possible.
2. Tester les performances
3. Optimiser les hotspots
4. Recommencer au point 2 a chaque nouvelle release de la JVM et au point 1
le plus souvent possible.




[snip]



Je te laisse faire le bug report chez Sun :-)


Oui.

[snip]



Et si on a

public class X {
public void f() {
List<Integer> ci = new ArrayList<Integer>();
List<String> cs = new ArrayList<String>();
...
}
}

il n'y a pas d'attribut Signature pour ci et cs. Il y a bien l'attribut
LocalVariableTypeTable mais il est purement optionnel et n'est pas présent
par defaut (uniquement avec javac -g pour debug info).


C'est exact. Je vais signaler le probleme a l'expert group.


De plus, comment veux tu traiter les cas suivants:

void f1() {
ArrayList<Integer> l1 = new ArrayList<Integer>();
l1.add(287);
List l2 = (List) l1.clone(); // clone is shallow
Integer i1 = l1.get(0);
Integer i2 = (Integer)l2.get(0);
assert(i1 == i2);
}

void f2() {
List<Integer> li = new ArrayList<Integer>();
Integer i = 365;
li.add(0, i);
Integer j = li.get(0);
assert (i == j);
}

void f3() {
List<Integer> li = new ArrayList<Integer>();
List ll = li; // warning
ll.add(new Object());
}


A vue de nez, ca parait difficile a optimiser. Mais je suis sur qu'il y a
une solution. Il y a toujours une solution.


[...]

Le fond du probleme reste que donner comme conseil de ne pas utiliser
l'auto(un)boxing avec les Collections pour des raisons de performance
est stupide, et tient plus du Voodoo que d'un raisonnement logique.



Je préfère de performances correctes aujourd'hui que d'être obligé
d'attendre une optimisation hypothétique de HotSpot...


Voir mon commentaire plus haut.

A part de just penser que HotSpot peut le faire, as-tu quelque chose
un peu plus tangible pour affirmer que HotSpot fait/fera cet optimisation?



Ca n'est pas une question de "si", mais de "quand".


1 2 3