2010-08-18 14 views
24

He visto muchos ejemplos primitivos que describen cómo funciona String Intern(), pero aún no he visto un caso de uso de la vida real que se beneficie de ello.Vida real, ejemplo práctico de utilizar String.intern() en Java?

La única situación que puedo soñar es tener un servicio web que recibe una cantidad considerable de solicitudes, cada una de naturaleza muy similar debido a un esquema rígido. Al internar() los nombres de los campos de solicitud en este caso, el consumo de memoria puede reducirse significativamente.

¿Alguien puede proporcionar un ejemplo de uso de intern() en un entorno de producción con gran éxito? ¿Tal vez un ejemplo de ello en una popular oferta de código abierto?

Editar: me refiero a la internación manual, no la internación garantizado de literales de cadena, etc.

Respuesta

1

No es una respuesta completa, pero la comida adicional para el pensamiento (found here):

Por lo tanto, la primaria El beneficio en este caso es que usar el operador == para cadenas internalizadas es mucho más rápido que usar el método equals() [para Cadenas no internalizadas]. Por lo tanto, use el método intern() si va a comparar cadenas más de una o tres veces.

+0

Esto es cierto, pero hay muchas excepciones a esta generalización: - Si las probabilidades de que sus cadenas tengan la misma longitud son mínimas, y el número de cadenas que posiblemente sea interno() 'es alto , uno podría argumentar que dado que equals() hace una verificación de tamaño primero, se expone innecesariamente a las excepciones OOM de PermGen. –

+0

Tienes razón, pero para el rendimiento tienes O (n) para iguales y O (1) para '=='. Estoy de acuerdo, que el peor de los casos solo ocurre si ambas cadenas tienen el mismo tamaño y solo difieren en el último char. Lo cual es usualmente un caso bastante raro. –

+2

La respuesta es incorrecta. Lo primero que hace String.equals es verificar la igualdad de referencia antes de verificar la igualdad semántica. Entonces, para dos cadenas internalizadas == y .equals son, bueno, iguales ... – PaulJWilliams

1

Teníamos un sistema de producción que procesa literalmente millones de datos a la vez, muchos de los cuales tienen campos de cadena. Nosotros debería haber estado intercediendo cadenas, pero había un error que significaba que no lo éramos. Al solucionar el error, evitamos tener que realizar una actualización de servidor muy costosa (al menos 6 cifras, posiblemente 7).

+1

¿Puede ser más específico? p. ¿Qué tipo de datos? ¿Fue impulsado por el usuario o conducido por interno/cron? ¿Qué se estaba haciendo con los datos? etc. Con este nivel de detalle, el ejemplo será un poco más claro. ¡Gracias! –

+1

Estoy limitado por lo que puedo revelar, pero esencialmente fue el procesamiento de transacciones financieras. Leemos toda una carga de datos de una base de datos masiva y realizamos operaciones de tipo depósito de datos a gran escala para discernir aspectos agregados. Algunos campos de texto en los datos no estaban siendo internados en la lectura de la base de datos, lo que lleva a una gran cantidad de memoria y una gran reducción en nuestra capacidad de procesamiento. – PaulJWilliams

0

Nunca, siempre, utilice el interno en los datos proporcionados por el usuario, ya que esto puede causar ataques de denegación de servicio (ya que las cadenas de intern() ed nunca se liberan). Puede hacer la validación en las cadenas proporcionadas por el usuario, pero nuevamente ha hecho la mayor parte del trabajo necesario para el interno().

+0

Su punto sobre el interno() 'ed Las cadenas que no se liberan son incorrectas (dependiendo de la JVM). Las JVM más relevantes usan referencias débiles para garantizar gc. –

21

internar puede ser muy beneficioso si usted tiene N cadenas que sólo puede tomar valores diferentes K, donde N supera con creces K. Ahora, en lugar de almacenar N cadenas en la memoria, solo estará almacenando hasta K.

Por ejemplo, puede tener un tipo ID que consta de 5 dígitos. Por lo tanto, solo puede haber 10^5 valores diferentes. Supongamos que ahora está analizando un documento grande que tiene muchas referencias/referencias cruzadas a los valores ID. Digamos que este documento tiene 10^9 referencias totales (obviamente, algunas referencias se repiten en otras partes de los documentos).

Así que N = 10^9 y K = 10^5 en este caso. Si no está intercediendo en las cadenas, estará almacenando cadenas 10^9 en la memoria, donde muchas de esas cadenas son equals (por Pigeonhole Principle). Si intern() la cadena ID que obtiene al analizar el documento, y no mantiene ninguna referencia a las cadenas no leídas que lee del documento (para que puedan ser basura), entonces nunca necesitará almacenar más que 10^5 cadenas en la memoria.

+2

Creo que esta es una evaluación casi perfecta, gracias por abstraerla de los polilenefrúicos.Mi dificultad para llegar a un ejemplo tangible radica en el hecho de que incluso en el caso anterior, la mayoría de las veces puede transmitir los datos de entrada y trabajar en ellos en fragmentos, todo a la vez. La transmisión por secuencias en lugar de la interna() (si corresponde) casi siempre sería preferible suponiendo una latencia/impacto de red insignificante en el caso de una fuente remota. La cosa es que nunca he visto un caso de uso que cumpla con el umbral de Strings necesario para considerar interno(), pero no se puede transmitir y dividir y conquistar. –

+1

@Tom: consulte también http://stackoverflow.com/questions/1356341/will-interning-strings-help-performance-in-a-parser relacionado; también está relacionado con el analizador y está motivado por el mismo principio de Pigeonhole. Un documento XML puede tener un millón de elementos '', pero probablemente solo unos pocos tipos de elementos. Puede internar los nombres de los elementos para que '' elemento "' solo aparezca una vez en la memoria (sin contar las instancias temporales de basura que se sueltan inmediatamente en lugar de su representante 'interno()'). – polygenelubricants

+0

es importante agregar que, desde Java 7 en adelante, las cadenas internas ya no viven en el espacio permgen, por lo que están sujetas a que se recolecte basura como cualquier otro objeto. (fuente: http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html) –

1

Ejemplos donde internación será beneficioso implican un cadenas grandes números donde:

  • las cadenas son probabilidades de sobrevivir a múltiples ciclos de GC, y
  • no es probable que sean múltiples copias de un gran porcentaje de la Instrumentos de cuerda.

Los ejemplos típicos implican dividir/analizar un texto en símbolos (palabras, identificadores, URI) y luego asociar esos símbolos a estructuras de datos de larga vida. El procesamiento de XML, la compilación del lenguaje de programación y las tres tiendas de RDF/OWL vienen a la mente como aplicaciones donde el internamiento es probable que sea beneficioso.

Pero internar no está exenta de problemas, especialmente si resulta que los supuestos anteriores no son correctos:

  • la estructura de datos de la piscina se utiliza para mantener las cuerdas internados toma más espacio,
  • internación toma time, y
  • interna no impide la creación de la cadena duplicada en primer lugar.

Por último, internar potencialmente aumenta los gastos generales de GC mediante el aumento del número de objetos que necesitan ser rastreado y copiado, y aumentando el número de referencias débiles que necesitan ser tratados. Este aumento en los gastos generales debe equilibrarse con la disminución de los gastos generales del GC que resulta de un internamiento efectivo.