java.lang.String limits
Facepalm with String limits S’il y a bien une chose que l’on peut très vite oublier avec Java, c’est la gestion de la mémoire. Et quand on fait des traitements lourds et longs, ça nous revient très rapidement en plein visage !
La limite que je pensais bien ne jamais rencontrer était bien celle-ci : la taille maximale d’une String
Reproduire le problème
Comment on fait pour l’atteindre ? Dans mon cas, on met dans une String l’intégralité des informations de chaque artefact d’un repository Maven. Plus simple, on agit de la sorte :
|
|
Je m’explique : dans la classe String, ce qui contient la chaîne de caractères c’est en fait un tableau de char. L’index du tableau, sous- entendu la taille de la String, est un int. Un int est stocké sous 32 bits, donc la valeur maximale que peut prendre un int est 2^31 -1 (cf la documentation en ligne : javadoc oracle)
Et donc si on arrive à mettre 2^31 caractères dans une String (via
StringBuilder dans mon cas) on se retrouve avec une belle
OutOfMemoryError
.
Là, on fait :
Moralité de l’histoire
Ne jamais se croire à l’abris d’une OutOfMemoryError car, même avec du TDD, DDD ou autre, je ne pense qu’il existe (sinon il doit se sentir bien seul..) de développeur qui aurait fait un test unitaire à base de plusieurs millions de caratères..
Je dois avouer que je ne suis trouvé un peu con sur ce coup-là.
Nota bene
Un collègue (Olivier Croisier) m’a
donné la bonne idée de passer par un Writer
ainsi, je ne stocke
pas de String et donc pas de OutOfMemoryError.
Autre fait important : l’output se fait en retour de HTTP GET. Avec un
traitement potentiellement long (celui qui me met +2^31 caractères dans
un String), on peut avoir des Timeout car la réponse n’est faite qu’en
un coup. Avec le Writer
, la réponse est donnée au fur et à mesure. En
combinant ça et HTTP 1.1 (mode connecté), plus de Timeout. La vie est
belle.