java string jvm-hotspot deduplication

Desduplicación de Java 8 String vs. String.intern()



jvm-hotspot deduplication (3)

Como referencias de comentarios, consulte: http://java-performance.info/string-intern-in-java-6-7-8/ . Es una referencia muy perspicaz y aprendí mucho, pero no estoy seguro de que sus conclusiones sean necesariamente de "talla única". Cada aspecto depende de las necesidades de su propia aplicación: ¡es muy recomendable tomar medidas de datos de entrada realistas!

El factor principal probablemente depende de lo que usted tiene el control sobre:

  • ¿Tienes control total sobre la elección de GC? En una aplicación de GUI, por ejemplo, todavía hay un caso sólido para usar Serial GC. (huella de la memoria total mucho más baja para el proceso: piense en 400 MB frente a ~ 1 GB para una aplicación moderadamente compleja, y es mucho más conveniente liberar la memoria, por ejemplo, después de un aumento transitorio en el uso). Así que puedes elegir eso o dar a tus usuarios la opción. (Si el montón sigue siendo pequeño, las pausas no deberían ser un gran problema).

  • ¿Tienes control total sobre el código? La opción G1GC es ideal para bibliotecas de terceros (¡y aplicaciones!) Que no puede editar.

La segunda consideración (según la respuesta de @ ZhongYu) es que String.intern puede desduplicar los propios objetos String , mientras que G1GC necesariamente solo puede desduplicar su campo char[] privado.

Una tercera consideración puede ser el uso de la CPU, por ejemplo, si el impacto en la duración de la batería de la computadora portátil puede ser de interés para sus usuarios. G1GC ejecutará un subproceso adicional dedicado a desduplicar el montón. Por ejemplo, jugué con esto para ejecutar Eclipse y descubrí que causó un período inicial de mayor actividad de la CPU después de la puesta en marcha (piense 1 - 2 minutos) pero se resolvió en un montón "en uso" más pequeño y nada obvio (solo ojo haciendo girar el administrador de tareas) la sobrecarga de la CPU o la ralentización posterior. Así que me imagino que un cierto% de un núcleo de CPU se utilizará en los periodos de desduplicación (¿durante? Después?) De alta rotación de memoria. (Por supuesto, puede haber una sobrecarga comparable si llama a String.intern en todas partes , que también se ejecuta en serie, pero luego ...)

Probablemente no necesite desduplicación de cadenas en todas partes. Probablemente hay solo ciertas áreas de código que:

  • realmente impactan el uso del montón a largo plazo, y
  • crear una alta proporción de cadenas duplicadas

Al utilizar String.intern selectiva, otras partes del código (que pueden crear cadenas temporales o semi-temporales) no pagan el precio.

Y, finalmente, un complemento rápido para la utilidad Guava: Interner , que:

Proporciona un comportamiento equivalente a String.intern() para otros tipos inmutables

También puedes usar eso para cuerdas. La memoria probablemente es (y debería ser) su principal preocupación de rendimiento, por lo que probablemente no se aplique con frecuencia: sin embargo, cuando necesita exprimir cada gota de velocidad de algún área de punto caliente, mi experiencia es que la referencia débil basada en Java Las soluciones HashMap se ejecutan de forma un poco más rápida que la implementación en C ++ de String.intern() de la JVM, incluso después de ajustar las opciones de jvm. (Y adicional: no es necesario ajustar las opciones de JVM para escalar a una entrada diferente).

Estoy leyendo sobre la característica en Java 8 actualización 20 para la deduplicación de cadenas ( más información ) pero no estoy seguro de si esto básicamente hace que String.intern() obsoleto.

Sé que esta función de JVM necesita el recolector de basura G1, que podría no ser una opción para muchos, pero suponiendo que uno utilice G1GC, ¿existe alguna diferencia / ventaja / desventaja de la deduplicación automática realizada por la JVM, en lugar de tener que realizar sus intern cadenas (una obvia es la ventaja de no tener que contaminar su código con llamadas a intern() )?

Esto es especialmente interesante teniendo en cuenta que Oracle podría hacer que G1GC sea el GC predeterminado en Java 9


Con esta función, si tiene 1000 objetos String distintos, todos con el mismo contenido "abc" , JVM podría hacer que compartan el mismo char[] internamente. Sin embargo, todavía tienes 1000 objetos String distintos.

Con intern() , solo tendrás un objeto String . Entonces, si su preocupación es el ahorro de memoria, intern() sería mejor. Ahorrará espacio, así como tiempo de GC.

Sin embargo, el rendimiento de intern() no es tan bueno, la última vez que escuché. Es posible que esté mejor teniendo su propio caché de cadenas, incluso usando un ConcurrentHashMap ... pero necesita un punto de referencia para asegurarse.


Quiero introducir otro factor de decisión con respecto a la audiencia objetivo:

  • Para un integrador de sistemas que tiene un sistema compuesto por muchas bibliotecas / marcos, con poca capacidad para influir en el desarrollo interno de esas bibliotecas, StringDeDuplication podría ser un ganador rápido si la memoria es un problema. Afectará a todas las cadenas en la JVM, pero G1 solo usará tiempo libre para hacerlo. Incluso puede modificar cuando la desduplicación se calcula utilizando otro parámetro (StringDeduplicationAgeThreshold)
  • Para un desarrollador que perfila su propio código, String.intern podría ser más interesante. Es necesario realizar una revisión exhaustiva del modelo de dominio para decidir si llamar a un interno y cuándo. Como regla general, puede usar interno cuando sepa que la Cadena contendrá un conjunto limitado de valores, como un tipo de conjunto enumerado (es decir, nombre del país, mes, día de la semana ...).