2009-03-25 12 views
14

¿Cuáles son los pro y los contras de mantener un conjunto de objetos de uso frecuente y obtener uno del grupo en lugar de crear uno nuevo? Algo así como la interna de cuerdas, excepto que será posible para todos los objetos de clase.Pool de objetos

Por ejemplo, puede considerarse bueno ya que ahorra tiempo de gc y tiempo de creación de objetos. Por otro lado, puede ser un cuello de botella de sincronización si se utiliza desde múltiples hilos, exige una desasignación explícita e introduce la posibilidad de pérdidas de memoria. Al retener la memoria que podría recuperarse, ejerce presión adicional sobre el recolector de basura.

+0

Los comentarios parecen negativos, pero estaba considerando algo similar. Tengo una aplicación j2me que crea miles de pequeños objetos de cuadro delimitadores latentes. Si puedo crear un grupo de ellos, entonces le daré al GC un trabajo más fácil más adelante. Me pregunto si esto sigue siendo una mala idea en el limitado mundo de los móviles. – izb

+0

Pool objetos costosos solamente (como conexiones de bases de datos y tal). La definición de "caro" depende en gran medida de sus requisitos. –

Respuesta

18

A menos que el objeto sea costoso de crear, no me molestaría.

Beneficios:

  • objetos creados Menos - si la creación de objetos es caro, esto puede ser significativo. (El ejemplo canónico es probable que las conexiones de base de datos, donde "creación" incluye hacer una conexión de red al servidor, que proporciona autenticación, etc.)

Desventajas:

  • código más complicado
  • recurso compartido = cierre; potencial cuello de botella
  • Viola las expectativas de GC de tiempos de vida del objeto (la mayoría de los objetos sean de corta vida)

¿Tiene usted un problema real que estamos tratando de resolver, o esto es especulativo? No pensaría en hacer algo como esto a menos que haya ejecuciones de benchmarks/profile que demuestren que hay un problema.

+0

De hecho, estoy interesado en reducir cualquier bloqueo mediante, por ejemplo, stop-the-world garbage collector en una aplicación sensible a la latencia en tiempo real. – baskin

+0

Bueno, podrías ver Java en tiempo real: nunca lo he usado, pero valdría la pena verificarlo. Intenta sintonizar el GC también, hay muchas opciones allí. Por supuesto, si puedes asegurarte de que tu código no asigna * ningún * objetos dentro del bit sensible a la latencia, eso es genial, pero difícil. –

+0

Sí, he visto el RTS de Java pero no estoy inclinado a usarlo principalmente porque no es gratis. La sintonización de GC también es algo que estoy probando, especialmente jugando con CMS gc. Es solo que no estoy logrando las combinaciones de parámetros óptimos correctos tal vez. Gracias por toda su ayuda jon. – baskin

2

Estoy de acuerdo con los puntos de Jon Skeet, si no tienes una razón específica para crear un grupo de objetos, no me molestaría.

Hay algunas situaciones en las que una agrupación es realmente útil/necesaria. Si tiene un recurso que es costoso de crear, pero puede reutilizarse (como una conexión de base de datos), podría tener sentido utilizar un grupo. Además, en el caso de las conexiones de bases de datos, un grupo es útil para evitar que sus aplicaciones abran demasiadas conexiones simultáneas a la base de datos.

21

Primera ley de optimización: no lo hagas. Segunda ley: no lo hagas a menos que hayas medido y sepas de hecho que necesitas optimizar y dónde.

Solo si los objetos son realmente caros de crear, y si realmente se pueden reutilizar (puede restablecer el estado con solo operaciones públicas a algo que pueda reutilizarse) puede ser efectivo.

Las dos ganancias que menciona no son realmente ciertas: la asignación de memoria en java es gratis (el costo fue cerca de 10 instrucciones de CPU, que no es nada). Por lo tanto, reducir la creación de objetos solo le ahorra el tiempo invertido en el constructor. Esto puede ser una ganancia con objetos realmente pesados ​​que pueden reutilizarse (conexiones de bases de datos, hilos) sin cambiar: reutiliza la misma conexión , el mismo hilo.

El tiempo del GC no se reduce. De hecho, puede ser peor. Con el movimiento de GC generacionales (Java es, o fue de hasta 1.5), el costo de una carrera de GC está determinado por la cantidad de objetos vivos, no por la memoria liberada.Los objetos vivos se moverán a otro espacio de la memoria (esto hace que la asignación de memoria sea tan rápida: la memoria libre es contigua dentro de cada bloque de GC) un par de veces antes de marcarse como antiguo y moverse al espacio de memoria de la generación anterior.

Los lenguajes de programación y soporte, como GC, se diseñaron teniendo en cuenta el uso común. Si te alejas del uso común en muchos casos, es posible que te resulte más difícil leer el código que es menos eficiente.

+0

De hecho, estoy interesado en reducir cualquier bloqueo diciendo, por ejemplo, el recolector de basura stop-the-world en una aplicación sensible a la latencia en tiempo real. Sin embargo, lo que dices tiene mucho sentido y estoy de acuerdo en que los puntos de referencia son necesarios para tomar esa decisión. – baskin

+2

El tiempo de GC * puede * reducirse, si al usar un grupo puede evitar tener que asignar objetos, por ejemplo, podría ser una ganancia significativa en una aplicación de baja latencia. Sin embargo, es un verdadero dolor asegurarse de que nunca asignes ... –

+0

(estoy de acuerdo en que también podría hacer que el tiempo del GC empeore muy fácilmente, por cierto) –

5

Do not.

Esto es 2001 pensando. El único objeto "pool" que todavía vale algo ahora es un singleton. Uso singletons solo para reducir la creación de objetos a fin de crear perfiles (para que pueda ver más claramente lo que está afectando el código).

Todo lo demás está fragmentando la memoria sin un buen propósito.

Adelante, ejecute un perfil para crear 1.000.000 de objetos. Es insignificante

Old article here.

+1

Dado el tiempo de inicialización posterior al constructor, es insignificante. –

9

Pooling significará que, por lo general, no puede hacer que los objetos inmutables. Esto lleva a una copia defensiva, por lo que terminas haciendo muchas más copias de las que obtendrías si acabas de crear un objeto nuevo inmutable.

La inmutabilidad no siempre es deseable, pero la mayoría de las veces encontrará que las cosas pueden ser inmutables. Hacerlos no inmutables para que puedas reutilizarlos en una piscina probablemente no sea una gran idea.

Así que, a menos que sepa con certeza que es un problema, no se moleste. Haga que el código sea claro y fácil de seguir, y es probable que sea lo suficientemente rápido. Si no es así, el hecho de que el código sea claro y fácil de seguir facilitará la aceleración (en general).

+1

+1 por conocer mi dolor. Acabo de resolver un error serio de corrupción de datos al eliminar un grupo de objetos. La generación de perfiles en Java 1.3 y 1.4 mostró que el grupo era una gran ganancia, en 1.5 desacelera el código. – Darron

+0

Depende de lo que acumules. –

5

que depende enteramente de lo caro que sus objetos son crear, en comparación con el número de veces que los crea ... por ejemplo, objetos que son sólo estructuras glorificados (por ejemplo, contienen sólo un par de campos, y no hay métodos distintos de los accesorios) puede ser un caso de uso real para la agrupación.

Un ejemplo de la vida real: necesitaba extraer repetitivamente los n elementos más altos (enteros) de un proceso que genera una gran cantidad de pares enteros/rangos. Utilicé un objeto "par" (un número entero y un valor de rango flotante) en una cola de prioridad limitada. Reutilizando los pares, versus vaciar la cola, tirar las parejas y volver a crearlas, produjo una mejora del 20% en el rendimiento ... principalmente en la carga del GC, porque las parejas nunca necesitaron ser reasignadas durante toda la vida de la JVM.

3

Los grupos de objetos generalmente son solo una buena idea para conexiones de bases de datos de objetos costosos. Hasta Java 1.4.2, los pools de objetos podrían mejorar el rendimiento pero a partir de los pools de objetos Java 5.0 donde es más probable dañar el rendimiento que la ayuda y se eliminaron los pools de objetos para mejorar el rendimiento (y la simplicidad)