¿Debería minimizar la creación de muchos objetos pequeños?

10

Al escribir algo que crea muchos (1000) de objetos pequeños a menudo, ¿debería tratar de minimizarlo para el rendimiento? Especialmente si no sabe en qué sistema se ejecutará, desde computadoras de escritorio de baja a alta gama o incluso móviles. Para dispositivos móviles, escuché que crear muchos objetos dificulta un poco el rendimiento, aunque no sé cuán cierto es eso.

Tengo un ejemplo que muestra bien esta idea. En un programa de gráficos, digamos que hay un método que se usa para todo el dibujo llamado idealmente drawPixel(Point). Podría haber miles de puntos creados y puede repetirse a menudo, como en un juego donde podría llamarse más de 60 veces por segundo. Alternativamente, drawPixel(int x, int y)podría usarse para minimizar la creación de muchos objetos Point.

En un diseño orientado a objetos, creo que sería preferible usar Point. Sin embargo, el uso de tipos primitivos puede aumentar el rendimiento. El aumento de rendimiento puede ser insignificante en la mayoría de los casos, pero no estoy seguro acerca de cosas como máquinas móviles o más antiguas. ¿Cuál es la ganancia de rendimiento al hacer algo como esto y es algo que debe tenerse en cuenta?

Stripies
fuente
Me está costando encontrar referencias para respaldar esto, pero en general en Java 8 no me preocupo por eso. No hagas cosas obviamente estúpidas, pero si no eres un derroche deliberado, el sistema debería funcionar bien. Sun / Oracle ha tenido alrededor de 20 años para ajustar el GC y la administración de memoria y se han vuelto muy buenos en eso.
@Snowman He oído que las versiones más nuevas de Java funcionan mejor con la administración de memoria, pero el problema que veo es que no hay garantía de que el usuario no esté usando una versión anterior. Eso es parte de lo que creó esta preocupación mía.
Stripies
1
Primero haga una medición de rendimiento. Si tiene algunos problemas, piense cómo optimizar. Pero no sacrifique el mantenimiento del código demasiado pronto porque cree que podría tener algunos problemas de rendimiento.
Visto el
2
@Stripies Rendimiento de objetos Java de corta duración ya respondidos en ¿Deberíamos evitar la creación de objetos en Java? . Sin embargo, si alguna vez tiene que manejar cientos de millones de tales objetos por segundo, solo en ese momento reconsidere este problema.
rwong
1
Si le preocupan las versiones anteriores de Java, verifíquelo cuando realice la instalación. Una JVM lo suficientemente vieja como para causar un problema con la administración de memoria, también tiene muchos problemas de seguridad bien conocidos, por lo que pedirles a los usuarios que actualicen les está haciendo un favor. System.getProperty("java.version")(o "java.vm.version") es un punto de partida.
Jerry Coffin

Respuestas:

17

En general, no , no debes evitar crear objetos por miedo a perder rendimiento. Hay varias razones para esto.

  1. Usar objetos es una especie de punto de usar Java. Evitarlos de forma preventiva es una señal de que la decisión de usar Java podría no haber sido la correcta para empezar.
  2. Los problemas de rendimiento son notoriamente difíciles de predecir. Nunca asumas que algo es un cuello de botella. Siempre mide. La ingeniería de rendimiento es casi siempre una cuestión de hacer pequeños cambios exactamente en el lugar correcto. No puede predecir el lugar correcto sin medir más de lo que puede predecir el efecto de un medicamento sin un experimento.
  3. El costo de la creación de objetos se sobreestima en gran medida. En una JVM moderna, básicamente equivale a incrementar un puntero (y con los recolectores de basura generacionales, el costo de administrarlo también es trivial). Hay muchos textos en Internet que le aconsejan que evite objetos, que use la agrupación de objetos, etc. Este consejo a veces fue correcto en la década de 1990; hoy es en su mayoría obsoleto. Es muy poco probable que obtenga un rendimiento suficiente para justificar el costo de desarrollo adicional y la complejidad introducida al evitar objetos o administrarlos usted mismo.

Dicho esto, hay lugares en los que convertir algo en un objeto no tiene sentido para empezar. Pasar dos coordenadas a una rutina de dibujo podría ser un caso así: el par de coordenadas no tiene una existencia independiente, no tiene identidad, se usa solo una vez y luego se descarta de inmediato, etc.

Si este es el caso, entonces seguro, adelante y pase dos intsegundos en lugar de envolverlos en un objeto. El objetivo de OOP no es que todo deba ser un objeto. El punto es que los objetos facilitan el desarrollo en lugares donde son la solución natural a un problema de representación de datos. No evite los objetos donde tengan sentido; no los presente donde no lo hacen.

Kilian Foth
fuente
2

Cuando contemple los impactos en el rendimiento antes de escribir el código, debe asumir que no sabe lo que está haciendo.

Hay un espacio muy pequeño para los objetos en Java versus primitivos. Cuanto más pequeños sean sus objetos, mayor será el porcentaje de sobrecarga. Sin embargo, hace mucho tiempo aprendí que las cosas que duplican n no son nada en comparación con las cosas que multiplican n por n.

Entonces, aunque sí, podría encontrar algún sistema que tuviera la mitad del impacto del tamaño o incluso un cuarto, pregúntese por qué realmente le importa. Las soluciones complicadas a este problema no serán bien recibidas. Particularmente porque sumergirse en dicho código será confuso. Los programadores confundidos escriben código incorrecto. Escriben n veces n código que debería ser n log n código. Y tardan más en hacerlo.

Ahora, si puedes ahorrarme espacio con algún truco que cabe en una bonita caja, no tengo que mirar dentro la mayor parte del tiempo, podemos hablar. Si es una caja, puedo cambiarla por otra caja cuando esa caja funcione mejor, incluso puedo pagarla.

naranja confitada
fuente
2

En el ajuste de rendimiento que he hecho ( ejemplo ) es muy fácil para la administración de memoria ser un gran culpable. No me importa lo loco que hayan sintonizado el nuevo operador y el recolector de basura, el cálculo más rápido es no computar. Entonces, si encuentro que el administrador de memoria toma un buen porcentaje de tiempo y no puedo evitar hacer objetos , entonces encuentro una manera de reutilizarlos, en lugar de crear constantemente nuevos.

Solo hago esto si tengo que hacer objetos. Para los gráficos, generalmente no. En mi humilde opinión, los gráficos deben ser dibujados , no construidos . Claro, se podría decir que una imagen consiste en puntos, líneas que los conectan, polígonos, texto, etc. Eso no significa que no tengas alternativa a hacer objetos con ellos antes de dibujarlos . Yo solo los dibujo.

Hay un método de pintura. Anulo eso, dibujo todo en un mapa de bits y luego bloqueo la transferencia a la pantalla. Se ve instantáneo. Para la entrada del mouse, hay métodos para anular, para detectar hacer clic, arrastrar, lo que sea.

OOP es una buena idea por ciertas razones. Esas razones no se aplican en todas las situaciones.

Mike Dunlavey
fuente
Estoy de acuerdo, pero también estoy de acuerdo con todos los demás en que las pruebas son la única forma de saberlo con certeza. Asegúrese de tener especificaciones que lo hagan de la manera simple / obvia antes de optimizarlo ... pero estoy de acuerdo en que lo nuevo todavía puede ser un problema.
Bill K
2

Siga adelante y use pequeñas asignaciones. Los administradores de memoria modernos, particularmente el administrador de objetos Java altamente optimizado, son extremadamente eficientes. Guarde la optimización de rendimiento principal para un programa de trabajo.

Es extremadamente probable que el rendimiento general sea adecuado. Si encuentra que ese no es el caso, entonces, y solo entonces , perfile el rendimiento del código. En una larga carrera de desarrollo de software, he aprendido que los cuellos de botella casi nunca están donde esperabas.

Una vez hice que un miembro del equipo pasara varios días haciendo que la búsqueda de miembros objeto fuera 20 veces más rápida. ¡Éxito! Sin embargo, la mejor aceleración general en el uso real se midió en centésimas de porcentaje. El cambio se retiró inmediatamente, ya que la aceleración requirió mayores asignaciones de memoria por miembro.

Bill Ferguson
fuente
1

Es simple: si necesitas 1000 objetos pequeños, entonces creas 1000 objetos pequeños y no te preocupes por eso. Si necesita 100 objetos pequeños, entonces crear 1000 objetos pequeños es estúpido: cree los que necesita y no más.

Si está preocupado por el rendimiento (y si no está preocupado también por el rendimiento), debe tener cualquier funcionalidad escrita una vez en un solo lugar, lo que hace que todo su código sea más simple y fácil de entender. Luego, si tiene un problema de rendimiento, la medición puede mostrarle que hay un lugar donde ocurre el problema de rendimiento, lo que facilita las cosas, y solo un lugar donde necesita cambiarlo. O medir muestra que este lugar no causa ningún problema, así que ya está.

gnasher729
fuente