2010-05-19 12 views
7

Estoy escribiendo un códec para procesar los mensajes enviados a través de TCP utilizando un protocolo de cable a medida. Durante el proceso de decodificación creo un número de String s, BigDecimal sy fechas. Los patrones de acceso de cliente-servidor significan que es común para el cliente para emitir una solicitud y luego decodificar miles de mensajes de respuesta, lo que resulta en un gran número de duplicarString s, s, etc. BigDecimal¿Usar el espacio PermGen o el método de prácticas internas de "rodar mi propio yo"?

Por lo tanto he creado una clase InternPool<T> que me permite internar cada clase de objeto. Internamente, el grupo usa un WeakHashMap<T, WeakReference<T>>. Por ejemplo:

InternPool<BigDecimal> pool = new InternPool<BigDecimal>(); 

... 

// Read BigDecimal from in buffer and then intern. 
BigDecimal quantity = pool.intern(readBigDecimal(in)); 

Mi pregunta: Estoy utilizando InternPool para BigDecimal pero debería también considerar el uso para Stringen lugar deString 's intern() método, que creo que utiliza el espacio PermGen? ¿Cuál es la ventaja de usar el espacio PermGen?

+1

@kts: Si tuviera que mapear byte [] a BigDecimal, entonces el byte [] no será referenciado por nada una vez que el grupo interno haya creado/devuelto el BigDecimal. Suponiendo que el byte [] es la clave en el WeakHashMap subyacente, esto provocaría que la entrada se elimine a pesar de que se esté utilizando el BigDecimal correspondiente. – Adamski

+1

¿Es 'WeakReference' apropiado para esto, o debería estar usando una' SoftReference'? El GC se comporta de manera diferente para ambos y parece que estás intentando crear un tipo de caché; las referencias débiles no son un buen uso para ese propósito. Vea mi respuesta aquí por algunas razones por las cuales: http://stackoverflow.com/questions/2861410/weakhashmap-iteration-and-garbage-collection/2862174#2862174 –

+0

@ Adamski Yo usaría una SoftReference en el BigDecimal solamente y una ReferenceQueue para elimine 'byte []' s del mapa una vez que se haya puesto en cola un BigDecimal. (Probablemente necesite un BiMap).Esto puede eliminar la construcción de objetos redundantes BigDecimal que ahorran memoria/tiempo de ejecución de gc y tiempo de ejecución (solo tienen que crearse una vez). – KitsuneYMG

Respuesta

2

Es posible que el grupo String.intern() de la JVM sea más rápido. AFAIK, está implementado en código nativo, por lo que en teoría es debería ser más rápido y usar menos espacio que un grupo implementado usando WeakHashMap y WeakReference. Tendría que hacer una evaluación comparativa cuidadosa para confirmar esto.

Sin embargo, a menos que tenga un gran número de objetos duplicados de larga duración, dudo que el internamiento (ya sea en permGen o con sus propios grupos) haga mucha diferencia. Y si la proporción de objetos únicos a duplicados es demasiado baja, la interna solo aumentará la cantidad de objetos activos (lo que hará que el GC tarde más tiempo) y reducirá el rendimiento debido a los gastos generales del interinato, y así sucesivamente. Así que también recomendaría la evaluación comparativa de los enfoques "interno" versus "no interno".

+0

Adamski tiene un gran número de objetos duplicados de larga vida :-) –

+0

@oxbow_lakes - muy inteligente. El punto es que necesita cuantificar estas cosas para determinar si el internamiento (por cualquier mecanismo) mejora el rendimiento ... o lo empeora. Y hay un * lote * de factores que afectan el resultado. –

4

Si ya tiene una clase InternPool, cree que es mejor usar eso que elegir un método de internamiento diferente para Cadenas. Especialmente desde String.intern() parece dar una garantía mucho más fuerte de lo que realmente necesita. Su objetivo es reducir el uso de memoria, de modo que la internación perfecta durante toda la vida útil de la JVM no es realmente necesaria.

también, que haría uso de la Google CollectionsMapMaker para crear un InternPool para evitar la re-creación de la rueda:

Map<BigDecimal,BigDecimal> bigDecimalPool = new MapMaker() 
    .weakKeys() 
    .weakValues() 
    .expiration(1, TimeUnits.MINUTES) 
    .makeComputingMap(
     new Function<BigDecimal, BigDecimal>() { 
     public BigDecimal apply(BigDecimal value) { 
      return value; 
     } 
     }); 

Esto le (implementado correctamente) claves y valores débiles, seguridad hilo daría, purga automática de entradas antiguas y una interfaz muy simple (un simple, bien conocido Map). Para estar seguro, también podría envolverlo usando Collections.immutableMap() para evitar que se estropee el código.

+0

OK Gracias. ¿Interno String.intern() durante el tiempo de vida de la JVM? No estoy seguro de que esto sea cierto, ya que pensé que las máquinas virtuales modernas recogían basura de PermGen. – Adamski

+0

@Joachim: pareces estar dando a entender que un String interno vivirá durante la vida de JVM. Esto no está garantizado por los javadocs, y de hecho no creo que sea cierto para las JVM recientes. –

+0

@Stephen: Intenté * no * dar a entender que, como JavaDoc de hecho no dice eso. –

Cuestiones relacionadas