Las cadenas son problemáticos
Básicamente en Java, String
referencias (cosas que utilizan char[]
detrás de las escenas) dominará la mayor parte negocio de la memoria aplicaciones sabia. La forma en que se crean determina la cantidad de memoria que consumen en la JVM.
Simplemente porque son tan fundamentales para la mayoría de las aplicaciones comerciales como tipo de datos, y también son uno de los que más hambre tienen en la memoria. Esto no es solo una cosa de Java, los tipos de datos String
ocupan mucha memoria en casi todos los idiomas y en la biblioteca de tiempo de ejecución, porque al menos son solo matrices de 1 byte por carácter o en el peor (Unicode) son matrices. de múltiples bytes por personaje.
vez al perfilar uso de CPU en una aplicación web que también tenía una dependencia JDBC de Oracle descubrí que StringBuffer.append()
dominaron a los ciclos de la CPU en muchos órdenes de magnitud con respecto a todas las demás llamadas a métodos combinado, mucho menos cualquier otra llamada al método individual. El controlador JDBC realizó muchas manipulaciones de String
, una especie de compensación por el uso de PreparedStatements
para todo.
Lo que usted está preocupado por que no se puede controlar, no directamente de todos modos
Lo que usted debe centrarse en lo que es en su control, que es asegurarse de que no se aferran a las referencias más largo que lo necesita, y que no está duplicando cosas innecesariamente. Las rutinas de recolección de basura en Java están altamente optimizadas, y si aprende cómo funcionan sus algoritmos, puede asegurarse de que su programa se comporte de la manera óptima para que esos algoritmos funcionen.
Java memoria de la pila no es como logró manualmente la memoria en otros idiomas, esas reglas no se aplican
Lo que se consideran pérdidas de memoria en otros idiomas no son la misma cosa/root como causa en Java con su sistema de recolección de basura.
Lo más probable es que en la memoria Java no se consuma un solo objeto uber que tenga fugas (referencia colgante en otros entornos).
lo más probable es un montón de asignaciones más pequeñas debido a StringBuffer
/StringBuilder
objetos no del tamaño adecuado en las primeras instantantations y luego tener que crecer de forma automática los char[]
arrays para almacenar posteriores append()
llamadas.
Estos objetos intermedios se pueden retener durante más tiempo de lo esperado por el recolector de basura debido al alcance que tienen y muchas otras cosas que pueden variar en el tiempo de ejecución.
Ejemplo: el recolector de basura puede decidir que no son candidatos, sino porque considera que hay un montón de memoria todavía no se tenía que podría ser el momento demasiado caro aconsejable eliminar a cabo en ese punto en el tiempo, y esperará hasta que la presión de la memoria aumente.
El recolector de basura es realmente bueno ahora, pero no es mágico, si estás haciendo cosas degeneradas, hará que no funcione de manera óptima. Hay una gran cantidad de documentación en Internet sobre la configuración del recolector de basura para todas las versiones de las JVM.
Estos objetos no referenciados pueden no haber llegado al tiempo que el recolector de basura cree que los necesita para borrarlos de la memoria, o podría haber referencias a ellos en algún otro objeto (List
) por ejemplo que no te das cuenta aún apunta a ese objeto. Esto es lo que comúnmente se conoce como fuga en Java, que es una fuga de referencia más específicamente.
Ejemplo: Si usted sabe que necesita para construir una 4K String
utilizando un StringBuilder
crearlo con no new StringBuilder(4096);
el valor por defecto, que es como 32 e inmediatamente se iniciará la creación de la basura que puede representar muchas veces lo que creo que el objeto debe ser tamaño sabio
Puede descubrir cuántos de los tipos de objetos se crean instancias con VisualVM, esto le dirá lo que necesita saber. No va a haber una gran luz intermitente que apunte a una sola instancia de una sola clase que diga: "¡Este es el gran consumidor de la memoria!", Es decir, a menos que haya una sola instancia de alguna char[]
que esté leyendo alguna archivo masivo en, y esto tampoco es posible, porque muchas otras clases usan char[]
internamente; y entonces ya casi lo sabías.
no veo ninguna mención de OutOfMemoryError
Es probable que no tiene un problema en su código, el sistema de recolección de basura simplemente podría no ser conseguir poner bajo presión suficiente para entran en juego y objetos desasignar que piensa que debería estar limpiando. Lo que cree que es un problema probablemente no lo es, a menos que su programa se bloquee con OutOfMemoryError
.Esto no es C, C++, Objective-C o cualquier otro lenguaje de gestión de memoria manual/tiempo de ejecución. No puede decidir qué hay en la memoria o no en el nivel de detalle que espera que pueda.
Utilizo un generador de perfiles que me muestra dónde se asignan los objetos. No sé si VisualVM puede hacer esto, pero es muy útil. El que yo uso es YourKit, pero no es gratuito (pero puedes obtener una licencia de evaluación) –
@PeterLawrey De hecho, leí una respuesta que escribiste hace un tiempo en la que mencionaste que tu kit era tu primera opción, lo busqué (ya que tu consejo siempre es increíble) pero sí es un poco caro y solo estoy aprendiendo. –
sin usar algo que instrumente su código, ningún analizador podrá señalar qué instancia == lo que usted llamó una referencia en su fuente. –