¿Qué es Java Cadena de la internación?


¿Qué es String Interning en Java, cuándo debo usarlo y por qué?

5 answers

Http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern()

Básicamente haciendo Cadena.intern() en una serie de cadenas se asegurará de que todas las cadenas que tengan el mismo contenido compartan la misma memoria. Así que si tienes una lista de nombres donde' john ' aparece 1000 veces, al internar te aseguras de que solo un 'john' tenga memoria asignada.

Esto puede ser útil para reducir los requisitos de memoria de su programa. Pero tenga en cuenta que la caché es mantenida por JVM en permanente memory pool, que normalmente tiene un tamaño limitado en comparación con heap, por lo que no debe usar intern si no tiene demasiados valores duplicados.


Más sobre las restricciones de memoria de usar intern ()

Por un lado, es cierto que puede eliminar duplicados de cadena por interiorizándolos. El problema es que las cadenas internalizadas van a la Generación Permanente, que es un área de la JVM que está reservada para objetos que no son de usuario, como Clases, Métodos y otras JVM internas objeto. El tamaño de esta área es limitado, y por lo general es mucho más pequeño que el montón. Llamar a intern() en una cadena tiene el efecto de mover de la pila a la generación permanente, y te arriesgas ejecución de PermGen space.

-- De: http://www.codeinstructions.com/2009/01/busting-javalangstringintern-myths.html


Desde JDK 7 (quiero decir en HotSpot), algo ha cambiado.

En JDK 7, las cadenas internadas ya no son se asignan en la generación permanente del montón de Java, pero en su lugar se asignan en la parte principal del montón de Java (conocido como las generaciones jóvenes y viejas), junto con los otros objetos creados por la aplicación. Este cambio dará lugar a más datos que residen en el montón principal de Java, y menos datos en la generación permanente, y por lo tanto puede requerir tamaños de montón para ser ajustado. La mayoría de las aplicaciones solo verán diferencias relativamente pequeñas en el uso del montón debido a este cambio, pero las aplicaciones más grandes que cargue muchas clases o haga un uso intensivo de la cadena.el método intern () verá diferencias más significativas.

From From Java SE 7 Características y mejoras

Actualización: Las cadenas internas se almacenan en el montón principal a partir de Java 7. http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html#jdk7changes

 181
Author: Ashwinee K Jha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-27 06:55:57

Hay algunas preguntas de "entrevista pegadiza" por qué obtienes

String s1 = "testString";
String s2 = "testString";
if(s1 == s2)System.out.println("equals!");

Si debe comparar las Cadenas Debe usar equals(). Lo anterior imprimirá iguales, porque el testString ya está internado para Usted por el compilador. Puede internar las cadenas usted mismo usando el método intern como se muestra en las respuestas anteriores....

 53
Author: maslan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-01 12:54:29

JLS

JLS 7 3.10.5 lo define y da un ejemplo práctico:

Además, un literal de cadena siempre se refiere a la misma instancia de la clase String. Esto se debe a que los literales de cadena - o, más generalmente, cadenas que son los valores de expresiones constantes (§15.28) - se "internan" para compartir instancias únicas, utilizando el método String.pasante.

Ejemplo 3.10.5-1. Literales de cadena

El programa que consiste en la unidad de compilación (§7.3):

package testPackage;
class Test {
    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.print((hello == "Hello") + " ");
        System.out.print((Other.hello == hello) + " ");
        System.out.print((other.Other.hello == hello) + " ");
        System.out.print((hello == ("Hel"+"lo")) + " ");
        System.out.print((hello == ("Hel"+lo)) + " ");
        System.out.println(hello == ("Hel"+lo).intern());
    }
}
class Other { static String hello = "Hello"; }

Y la unidad de compilación:

package other;
public class Other { public static String hello = "Hello"; }

Produce la salida:

true true true true false true

JVMS

JVMS 7 5.1 dice dice que el interning se implementa mágicamente y eficientemente con una estructura CONSTANT_String_info dedicada (a diferencia de la mayoría de los otros objetos que tienen representaciones más genéricas):

Un literal de cadena es una referencia a una instancia de la clase String, y se deriva de una estructura CONSTANT_String_info (§4.4.3) en la representación binaria de una clase o interfaz. La estructura CONSTANT_String_info da la secuencia de puntos de código Unicode que constituyen el literal de cadena.

El lenguaje de programación Java requiere que literales de cadena idénticos (es decir, literales que contienen la misma secuencia de puntos de código) deben referirse a la misma instancia de cadena de clase (JLS §3.10.5). Además, si la cadena de método.intern es llamado en cualquier cadena, el resultado es una referencia a la misma clase instancia que sería devuelta si esa cadena apareciera como un literal. Por lo tanto, la siguiente expresión debe tener el valor true:

("a" + "b" + "c").intern() == "abc"

Para derivar un literal de cadena, la Máquina Virtual Java examina la secuencia de puntos de código dados por la estructura CONSTANT_String_info.

  • Si la cadena de método.intern ha sido llamado previamente en una instancia de cadena de clase que contiene una secuencia de puntos de código Unicode idénticos a los dados por el CONSTANT_String_info estructura, entonces el resultado de la derivación literal de cadena es una referencia a la misma instancia de la clase String.

  • De lo contrario, se crea una nueva instancia de cadena de clase que contiene la secuencia de puntos de código Unicode dados por la estructura CONSTANT_String_info; una referencia a esa instancia de clase es el resultado de la derivación literal de cadena. Finalmente, se invoca el método intern de la nueva instancia de cadena.

Bytecode

Vamos a descompilar algunos OpenJDK 7 bytecode para ver internando en acción.

Si descompilamos: {[28]]}

public class StringPool {
    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        System.out.println(a);
        System.out.println(b);
        System.out.println(a == c);
    }
}

Tenemos en la piscina constante:

#2 = String             #32   // abc
[...]
#32 = Utf8               abc

Y main:

 0: ldc           #2          // String abc
 2: astore_1
 3: ldc           #2          // String abc
 5: astore_2
 6: new           #3          // class java/lang/String
 9: dup
10: ldc           #2          // String abc
12: invokespecial #4          // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne     42
38: iconst_1
39: goto          43
42: iconst_0
43: invokevirtual #7          // Method java/io/PrintStream.println:(Z)V

Observe cómo:

  • 0 y 3: la misma ldc #2 constante se carga (los literales)
  • 12: se crea una nueva instancia de cadena (con #2 como argumento)
  • 35: a y c se comparan como objetos regulares con if_acmpne

La representación de constante strings es bastante mágico en el bytecode:

  • tiene una estructura dedicada CONSTANT_String_info , a diferencia de los objetos regulares (por ejemplo, new String)
  • la estructura apunta a una Estructura CONSTANT_Utf8_info que contiene los datos. Ese es el único dato necesario para representar la cadena.

Y la cita de JVMS anterior parece decir que siempre que el Utf8 apuntado es el mismo, entonces se cargan instancias idénticas por ldc.

He hecho pruebas similares para campos, y:

  • static final String s = "abc" apunta a la tabla de constantes a través del atributo ConstantValue
  • los campos no finales no tienen ese atributo, pero aún pueden inicializarse con ldc

Conclusión : hay soporte directo de bytecode para el grupo de cadenas, y la representación de memoria es eficiente.

Bonus: compare eso con el Integer pool , que no tiene soporte directo de bytecode (es decir, no CONSTANT_String_info analógico).

 31
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-21 08:31:36

Actualización para Java 8 o plus . En Java 8, el espacio PermGen (Generación Permanente) se elimina y se reemplaza por Espacio Meta. La memoria del grupo de cadenas se mueve al montón de JVM.

En comparación con Java 7, el tamaño del grupo de cadenas aumenta en el montón. Por lo tanto, tiene más espacio para cadenas internalizadas, pero tiene menos memoria para toda la aplicación.

Una cosa más, ya sabes que al comparar 2 (referencias de) objetos en Java, se usa' ==' para comparar la referencia del objeto, 'equals ' se usa para comparar el contenido del objeto.

Vamos a comprobar este código:

String value1 = "70";
String value2 = "70";
String value3 = new Integer(70).toString();

Resultado:

value1 == value2 ---> verdadero

value1 == value3 ---> false

value1.equals(value3) ---> verdadero

value1 == value3.intern() ---> verdadero

Es por eso que debe usar 'equals' para comparar 2 objetos de cadena. Y así es como intern() es útil.

 2
Author: nguyentt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-07 20:39:55

La internación de cadenas es una técnica de optimización del compilador. Si tiene dos literales de cadena idénticos en una unidad de compilación, el código generado garantiza que solo haya un objeto de cadena creado para toda la instancia de ese literal(caracteres encerrados entre comillas dobles) dentro del ensamblado.

Soy del fondo de C#, así que puedo explicarlo dando un ejemplo de eso:

object obj = "Int32";
string str1 = "Int32";
string str2 = typeof(int).Name;

Resultado de las siguientes comparaciones:

Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true    
Console.WriteLine(obj == str2); // false !?

Nota1: Los objetos son comparado por referencia.

Note2 : typeof(int).Name se evalúa mediante el método de reflexión, por lo que no se evalúa en tiempo de compilación. Aquí estas comparaciones se hacen en tiempo de compilación.

Análisis de los Resultados: 1) true porque ambos contienen el mismo literal y por lo tanto el código generado tendrá solo un objeto que hace referencia a "Int32". Véase la nota 1.

2) true porque el contenido de ambos se comprueba el valor que es el mismo.

3) FALSO porque str2 y obj no tienen el mismo literal. Véase Nota 2.

 0
Author: Robin Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-24 04:51:15