Buscar
Social
Ofertas laborales ES

Foro sobre Java SE > Tiempos con String.intern() en java 7

Hola.

Estoy viendo como programar a partir de buenas practicas, en concreto siguiendo el siguiente enlace http://www.precisejava.com/javaperf/j2se/StringAndStringBuffer.htm#Strings101, por la fecha supongo que es algo viejo, 2005. La cuestión, en el articulo, se dice lo siguiente:

Con el metodo String.intern() evitamos duplicar objetos String en la memoria, el metodo comprobará si existe el String y en caso de existir nos devolvera la referencia al objeto, esto nos hara ganar tiempo a la hora de ejecutar y reduce el gasto de memoria, esto ultimo lo agrego yo.

El problema que al ejecutar el siguiente codigo la parte en la que utilizo el String.intern(), gasta mas tiempo que creado objetos sin el metodo, directamente con new. He estado mirando y al parecer java 7 trae una nueva implementación, en la que entra en juego el recolector de basura pero no me queda del todo claro.

¿Alguien me puedo orientar un poco con el tema? ¿No deberia de ser mas rapido crear Strings con el metodo intern()?

public class Ejemplo2_Strings {


public static void
main( String args[] )
{
long startTime, endTime;
String variables[] = new String[ 50000 ];

/**
* Creación de los objetos String
*/
for( int i=0; i< variables.length; i++ )
{
variables[i] = "s"+ i;
}

/**
* Ejemplo :: String Literal
*/

startTime = System.currentTimeMillis();
for( int i=0; i< variables.length; i++ )
{
variables[i] = "Hola";
}

endTime = System.currentTimeMillis();

System.out.println(
"\nTiempo gastado en la creación de los String literales :: "+ (endTime - startTime) + " milisegundos");

long startTime1, endTime1;

/**
* Ejemplo :: Objetos String
*/

startTime1 = System.currentTimeMillis();

for( int i=0; i< variables.length; i++ )
{
variables[i] = new String("Hola");
}

endTime1 = System.currentTimeMillis();

System.out.println(
"Tiempo gastado en la creación de los Objetos String sin el metodo intern() :: "+ (endTime1 - startTime1) + " milisegundos\n");

long startTime2, endTime2;

/**
* Ejemplo :: Objetos String con el metodo String.intern()
*/

startTime2 = System.currentTimeMillis();

for( int i=0; i< variables.length; i++ )
{
variables[i] = new String("Hola").intern();
}

endTime2 = System.currentTimeMillis();

System.out.println(
"Tiempo gastado en la creación de los Objetos String con el metodo String.intern() :: "+ (endTime2 - startTime2) + " milisegundos\n");

}

}

octubre 11, 2013 | Unregistered Commenterpr0kd

Una detallada discusión, muy técnica, sobre la cuestión:

http://stackoverflow.com/questions/1091045/is-it-good-practice-to-use-java-lang-string-intern

Que incluye otros enlaces interesantes.

octubre 11, 2013 | Registered Commenterchoces

Buenas,

Estas comparando esto
new String("Hola");
Con esto:
new String("Hola").intern();

En este ultimo caso haces dos operacionesµ. Creas el objeto y luego lo internalizas, cambiando la referencia al valor existente en el pool de constantes.

Lo que debes comparar es esto:
variables[i] = new String("Hola");
Por esto:
variables[i] = "Hola" (o bien "Hola".intern(), que es exactamente lo mismo para el compilador)

La diferencia en Java7 es que el valor internalizado se almacena tambien en el Heap en lugar de en el PermGen. Sin embargo deberia seguir siendo mucho mas eficiente tanto en velocidad como en memoria, sobre todo por el hecho de que se pueden hacer comparaciones mediante == en lugar de utilizar el equals.

Un saludo

octubre 11, 2013 | Unregistered CommenterUnoPorAhi

Gracias por las respuestas. Saltando por los distintos enlaces y googleando un poco mas empiezo a ver tierra! :). Por lo que he entendido intern() nos ahorra memoria aunque nos gasta mas tiempo de ejecución. Ejecutando el codigo de arriba con la opción -XX:+PrintGCDetails (otra cosa que me llevo ), modificando entre new String("Hola") y "Hola".intern() si que parece que la segunda forma da mas memoria aunque el tiempo sigue siendo superior.

Os dejo unos enlaces que me parecen interesantes por si a alguno le sirve...

https://blog.codecentric.de/en/2012/03/save-memory-by-using-string-intern-in-java/
https://blog.codecentric.de/en/2010/01/java-outofmemoryerror-a-tragedy-in-seven-acts/
http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html

Un saludo.

octubre 11, 2013 | Unregistered Commenterpr0kd

No, te basta con cambiarlo simplemente por "Hola" y el compilador lo intenalizara automaticamente, como puedes comprobar si por ejemplo haces comparaciones con ==. Parece que hacer explicitamente el .intern() (me he colado diciendo que es equivalente) si que es costoso porque implica una llamada nativa (JNI) a la JVM.
http://stackoverflow.com/questions/7263399/why-is-string-intern-so-slow

P.D yo para hacer este tipo de pruebas de rendimiento te recomendaria mejor que uses JUnitBenchmarks. Es muy facil de usar:
http://labs.carrotsearch.com/junit-benchmarks.html


Un saludo

octubre 11, 2013 | Unregistered CommenterUnoPorAhi

Si fallo mio, en este ejemplo segun entiendo seria igual que poner "Hola" incluso mas lento, cuando escribi tenia en mente un ejemplo que aparece en el primer enlace en el que una propieda de varios objetos comparten un mismo valor, ponia el ejemplo de usuarios con la misma región:

String city = resultSet.getString(1);
String region = resultSet.getString(2);
String countryCode = resultSet.getString(3);

Location location = new Location(city.intern(), region.intern(), countryCode.intern(), long, lat);

La verdad.. entiendo lo que realiza la función pero la utilidad.. aun no lo tengo del todo claro, ya que con el ejemplo anterior, java pasa valores por referencia, entonces.. ¿porque usar intern() en el contructor? ¿Para liberar las String que le preceden?

He estado probando MAT, un plugin de eclipse pero me guardo esta otra opción de JUnitBenchmark tambien :P.

Saludos.

octubre 12, 2013 | Unregistered Commenterpr0kd

Perdon por el doble post, pero revisando el primer enlace he visto que dice que las cadenas hardcodeadas son automaticamente internalizadas pero supongo que los valores que estan dentro de objetos instanciados no lo estan con lo cual puede dar lugar a valores duplicados ¿es esta la razón por la que se usa en el caso anterior el intern()? en este caso si veo utilidad al metodo.

octubre 12, 2013 | Registered Commenterpr0kd