Fuite mémoire dans java.text.DecimalFormat de GnuClasspath

Aujourd’hui, un collègue me montre du code qui utilise java.text.DecimalFormat de GnuClasspath, la JCL du projet GNU, et qui plante avec une java.lang.OutOfMemoryError.

L’objectif est de formater un double suivant un nombre de décimal, ce que fait très bien la classe java.text.DecimalFormat.

Voici la stacktrace complète de mon code de test :

Exception in thread "main" java.lang.OutOfMemoryError
at java.util.ArrayList.ensureCapacity(ArrayList.java:176)
at java.util.ArrayList.add(ArrayList.java:340)
at java.text.DecimalFormat.addAttribute(DecimalFormat.java:2236)
at java.text.DecimalFormat.handleFractionalPart(DecimalFormat.java:2074)
at java.text.DecimalFormat.formatInternal(DecimalFormat.java:1942)
at java.text.DecimalFormat.format(DecimalFormat.java:387)
at java.text.NumberFormat.format(NumberFormat.java:818)
at trash.MyTrash.testNewDecimal(MyTrash.java:34)
at trash.MyTrash.(MyTrash.java:18)
at trash.MyTrash.main(MyTrash.java:8)

Commençons les investigations de java.text.DecimalFormat.

(Lire la suite…)

Conversion d’un entier vers une chaîne de caractères

Au cours d’une relecture de code, je tombe sur cette ligne :

int myInt = 1979;
byte[] foo = ("" + myInt).getBytes();

L’objectif de ce code étant de récupérer un tableau de byte d’un entier en passant par une chaîne de caractères et ça fonctionne ! Mais cela est-il performant ?
(Lire la suite…)

Chaîne de caractères littérales et objet String

Les spécifications de Java expliquent que les chaînes de caractères littérales sont une suite vide ou de plusieurs caractères entre guillemets. Ceci correspond donc au type String. Par conséquent le langage Java permet de créer des chaînes de caractères de deux manières différentes :

// Initialisation de la chaîne de caractères
// par la construction de l'objet String
String foo = new String("Hello World foo");
 
// Initialisation de le chaîne de caractères
// par affectation d'une chaîne de caractères littérale
String bar = "Hello World bar";

On peut se demander si le compilation de ce code donne le même code intermédiaire (bytecode) ou pas.
(Lire la suite…)

Le combat : String vs StringBuilder vs StringBuffer

L’objet String est immuable, c’est à dire que son état ne peut pas être modifié après sa création, et toute manipulation entraînera la création d’un nouvel objet ce qui peut diminuer les performances de la JVM.

Pour pallier à ce problème de performance, la classe StringBuffer permet de manipuler des chaînes de caractères sans créer à chaque changement un nouvel objet. Cette classe est méconnue mais existe depuis le JDK 1.0 !

Cependant, il faut savoir que toutes les méthodes de la classe StringBuffer sont synchronisées, elle est dite thread-safe ! Ceci est indispensable si la chaîne de caractères peut être accédée de manière concurrente sinon c’est inutile.

Heureusement, depuis Java 1.5, la nouvelle classe StringBuilder est une copie de StringBuffer mais avec des méthodes non synchronisées permettant ainsi  d’améliorer les performances pour la manipulation de chaînes de caractères sans accès concurrent.

J’ai écrit un petit test pour illustrer tout cela.
(Lire la suite…)

Manipulation de String : equals(Object anObject) vs isEmpty()

Pour commencer la semaine tranquillement, je fais un peu de relecture de code et je bloque là-dessus :

final String errorMessage; // Get a string from anywhere !
 
if (!errorMessage.equals("")) {
   // Do something
}

Pourquoi ne pas utiliser la méthode isEmpty(), disponible depuis Java 1.6, qui semble plus lisible et pratique à utiliser :

final String errorMessage; // Get a string from anywhere !
 
if (!errorMessage.isEmpty()) {
   // Do something
}

Peut être par un souci de performance…

(Lire la suite…)

Analyse de la méthode values() des énumérés

Un collègue me demande si la méthode values() des énumérés ne créé pas de nouveau objet. N’étant pas sûr de ma réponse, je me lance donc dans l’analyse.

La classe Enum de Java comporte une méthode values() pour récupérer toutes les valeurs de l’énuméré dans un tableau, prenons l’exemple de code suivant :

public enum Days {Monday, Tuesday};
 
public EnumValues() {
   Days.values();
}

L’analyse du bytecode montre uniquement un appel à l’opcode INVOKESTATIC :

LINENUMBER 7 L1
INVOKESTATIC EnumValues$Days.values()[LEnumValues$Days;
POP

Mais où est donc le code de la méthode values() ?

(Lire la suite…)

Les tableaux de type primitif dans le tas ou la pile ?

Les développeurs savent que toutes les déclarations locales de type primitif dans une méthode sont désallouées dès la sortie de la méthode car les allocations sont faites dans la pile (stack). Exemple :

private void test() {
   int i = 1979;
   long j = 1989;
}

Les variables « i » et « j » seront désallouées dès la sortie de la méthode « test()« . Mais quand est-il des tableaux de type primitf ?

(Lire la suite…)

Programmation Java sur GPU : c’est possible !

Pour une fois, l’article ne parle ni de Java temps réel ni de Java embarqué mais plutôt de la possibilité d’écrire du code Java sur les processeurs graphiques (GPU) afin de bénéficier de leur puissance de calcul.

Aujourd’hui, pour programmer sur des GPUs, les deux principaux langages disponibles sont OpenCL et CUDA. Il existe donc deux solutions pour le Java :

  • l’API Aparapi (A PARallel API), développée conjointement par AMD et Nvidia, pour transcrire le code Java en OpenCL pour s’exécuter sur le GPU
  • l’API jCUDA pour s’interfacer directement avec CUDA

Voici quelques liens sur Aparapi :

Voici quelques liens sur jCUDA :

L’intérêt de la programmation Java sur GPU est de bénéficier de la puissance de calcul de celui-ci mais le problème commun de cette méthode est le goulet d’étranglement du bus entre le CPU et le GPU qui peuvent limiter les transferts de données.

Utiliser le cache des types enveloppés

Les types enveloppés sont des objets représentants les types primitifs agrémentés de méthodes utilitaires. Parmi celles-ci, la méthode valueOf permet de retourner un type enveloppé à partir d’un type primitif comme le montre l’exemple suivant :

Integer value = Integer.valueOf(5);

En lisant le code source des méthodes valueOf des types enveloppés, je me suis aperçu que celles-ci utilisent un cache contenant un certain nombre de types enveloppés initialisés statiquement au chargement de la classe. Du coup, la méthode valueOf retourne soit un type enveloppé déjà instancié depuis le cache, soit un nouveau type enveloppé.

(Lire la suite…)