java - ¿String.intern() realmente aumenta el rendimiento?
string-interning (2)
Hice una pequeña investigación para descubrir cómo se implementa el método String.intern()
en java.
Miré la implementación en C ++ del grupo Intern desde Open JDK 6 y allí vi un HashSet
simple. Para mí, significó que cuando alguien está tratando de internar una String
los siguientes pasos deben realizarse:
- encontrar código hash asociado con la
String
dada - encontrar un cubo apropiado
- comparando la cadena dada con todas las otras cadenas en el cubo. Antes de este paso puede haber 0 cadenas, una cadena o LOTE de cadenas en el cubo. Por lo tanto, si la cadena dada ha sido colocada previamente en el cubo, obtendremos al menos una comparación (ese es el mejor de los casos. Por supuesto, puede haber muchas colisiones y ahora hay muchas otras cadenas en el cubo)
- Si se ha encontrado la Cadena en el depósito, debe devolverse con el método
intern()
- Si no se ha encontrado la Cadena en el cubo, se debe colocar en el cubo y devolverse con el método
intern()
str1.intern() == str2.intern()
gente dice que str1.intern() == str2.intern()
sería más rápido que str1.equals(str2)
.
Pero no puedo ver la razón por la que debería ser más rápido.
Como puedo ver en el caso de str1.equals(str2)
siempre tenemos dos cadenas que comparan char por char en el método String.equals()
.
En el caso de str1.intern() == str2.intern()
, cuántas comparaciones tendríamos que obtener o poner la cadena a / desde la agrupación (correcto, puede haber muchas comparaciones y son simples caracteres por comparaciones de caracteres también)?
Entonces, en el caso de str1.intern() == str2.intern()
incluso si usamos ==
para comparar cadenas, también tendremos muchas acciones adicionales, como las comparaciones descritas anteriormente.
Cuando lo entendí, decidí hacer algunas pruebas de referencia.
Los primeros resultados me mostraron que str1.intern() == str2.intern()
era más rápido que str1.equals(str2)
.
Este comportamiento fue causado por el hecho de que el método String.intern()
es nativo, por lo que no debe interpretarse cada vez que String.equals()
es un método java.
Entonces decidí usar la opción -Xcomp
para hacer que JVM compile todo el código al inicio.
Después de eso es igual a una velocidad mejor que interna.
Lo probé en Java 6 y 7.
Así que mi pregunta es: ¿alguna vez has visto una situación al internar una mayor velocidad de comparación de cuerdas? Yo sí, ¿cómo puede ser?
¿O quizás intern()
solo puede ayudar a ahorrar más memoria libre?
A su pregunta sobre por qué str1.intern() == str2.intern()
puede ser más rápido:
Esta es la implementación de String.equals()
, como puede ver, puede ser muy ineficiente dependiendo de las cadenas comparadas.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Tus pasos pueden ser mucho más rápidos:
1) hashCode () se calcula una vez para cualquier String debido a su inmutabilidad y es bastante rápido
2) encontrar el cubo es O (1)
3) comparando su String con otros en el mismo grupo, puede que haya algunos, pero aún así debería ser más rápido que equals()
4) y 5) son rápidos
Y no olvide que las operaciones anteriores deberán realizarse una sola vez para cualquier String, una vez que esté intern()
el resultado se devuelve de la primera comparación.
String.intern()
está destinado a disminuir el uso de la memoria .
Solo use cadenas internadas (si alguna vez) cuando tenga muchas, muchas copias múltiples de la misma cadena en la memoria. internando las cadenas, todas esas copias usarán la misma referencia.
Solo he visto que las cadenas internas son útiles cuando tengo millones de copias de la misma cadena.
Al igual que con cualquier tipo de optimización, solo hágalo después de que haya un problema de rendimiento o de memoria y lo haya perfilado para que haya detectado que este es el cuello de botella.
Consulte esta publicación de blog para obtener más detalles sobre el internado de cadenas.