2008-10-20 26 views
5

Soy un programador de C++ y estoy jugando con Java después de encontrar JPA que para algunas de mis aplicaciones actuales es un envío de dios. No he tocado Java desde la universidad y tengo problemas para quedarme sin espacio. Estoy usando el siguiente código como la parte principal de una prueba no muy grave de jdbc/jpa/lucene, pero sigo obteniendo excepciones OutOfMemory aleatorias.administración de memoria java

 EntityManager em = emf.createEntityManager(); 
     Query q = em.createQuery("select p from Product p" + 
      " where p.productid = :productid"); 
     Connection con = DriverManager.getConnection("connection string"); 
     Statement st = con.createStatement(); 

     IndexWriter writer = new IndexWriter("c:\\temp\\lucene", new StandardAnalyzer(), IndexWriter.MaxFieldLength.LIMITED); 

     ResultSet rs = st.executeQuery("select productid from product order by productid"); 
     while (rs.next()) { 
      int productid = rs.getInt("PRODUCTID"); 
      q.setParameter("productid", productid); 
      Product p = (Product)q.getSingleResult(); 

      writer.addDocument(createDocument(p)); 
     } 

     writer.commit(); 
     writer.optimize(); 
     writer.close(); 

     st.close(); 
     con.close(); 

no voy a publicar todos createDocument pero todo lo que hace es crear una instancia de un nuevo org.apache.lucene.document.Document y agrega campos a través de add (nuevo campo ...), etc Hay alrededor de 50 campos en total y la mayoría son cadenas cortas (< 32 caracteres) de longitud.

En mi "newby-ness" hay algo completamente estúpido que estoy haciendo (o no) que haría que las cosas no se GC'd?

¿Existen mejores prácticas con respecto a la administración de la memoria Java y hacer cosquillas al GC?

Respuesta

3

No veo nada obviamente fuera de lugar. Si está trabajando con una base de datos muy grande, puede intentar aumentar su tamaño de almacenamiento dinámico utilizando la opción -Xmx n en su invocación de JVM. Por lo general, esta no es la mejor solución, solo haga esto cuando sepa que el tamaño de su conjunto de trabajo es realmente mayor que el tamaño de pila predeterminado.

¿Está utilizando estructuras de datos complejas? Si tiene referencias circulares entre objetos, puede evitar que el recolector de basura limpie objetos inalcanzables. Si tiene estructuras de datos escritas a mano, asegúrese de anular explícitamente las referencias a los objetos que se eliminan en lugar de hacer algo como disminuir una variable de tamaño.

+1

GC no tiene problemas con las referencias circulares, los objetos seguirán siendo eliminados. No estoy seguro de entender lo que quiere decir con referencias explícitamente nulas a los objetos. ¿De qué otra manera los eliminarías? – Robin

+0

La otra forma de eliminarlos es dejarlos fuera del alcance. Establecer explícitamente referencias a null es para la combinación de objetos enormes y bucles largos, donde la referencia del objeto se mantendría en la memoria durante un tiempo prolongado. – gnud

0

¿Cuántos elementos hay en su conjunto de resultados? Si hay suficientes registros, entonces usará toda su memoria, ya que no hay nada de basura recolectada en este caso, ya que está haciendo un addDocument para el escritor, que tendrá una referencia a todos los documentos que está creando.

2

Bueno ...

larga experiencia con Java y bases de datos (an example post PostgresSQL Diferencias en MySQL Oracle>) me ha enseñado que los controladores JDBC que usamos al hacer esta obra con frecuencia tienen problemas.

Tengo un código que necesita permanecer conectado a una base de datos 24/7 y debido a una fuga de memoria del controlador, la JVM siempre se ahogaría en algún momento. Entonces, escribí el código para detectar la excepción específica lanzada y luego tomo medidas cada vez más drásticas, incluyendo desconectar la conexión y volver a conectar e incluso reiniciar la JVM de forma desesperada, nada funciona para solucionar el problema. ¡Qué DOLOR tener que escribirlo, pero funcionó hasta que el proveedor de DBMS salió con un nuevo controlador JDBC que no causó el problema ... De hecho, dejé el código en su lugar, por si acaso!

... Por lo tanto, no podría ser nada lo que está haciendo.

Tenga en cuenta que llamar al recolector de basura fue una de las estrategias que utilicé, pero las métricas mostraron que rara vez me ayudó.

Además, puede no estar claro, pero los ResultSets mantienen una conexión continua con el motor de la base de datos, en muchos casos (a menos que se establezca explícitamente de otra manera) bidireccional, incluso si solo está leyendo. Y, algunos controladores JDBC le permiten pedir una conexión mono-direccional, pero mienten y devuelven uno bidireccional. ¡Ten cuidado con esto!

Por lo tanto, es una buena práctica descargar los objetos ResultSet en otros objetos para mantener los valores y soltar los objetos ResultSet tan pronto como sea posible.

Buena suerte. RTIII

0

Java mantiene varios grupos de memoria diferentes, y quedarse sin uno de ellos puede causar la temida excepción OutOfMermoryException. Los problemas de asignación de memoria por parte del sistema operativo también pueden manifestarse como un OOM.

Debería ver un seguimiento de pila detallado, o posiblemente un archivo de volcado de error en el directorio de la aplicación, que puede proporcionar más pistas sobre el problema.

Si utiliza un perfil decente (JVisualVM que se envía con Sun Java 6 JDK recientes es probablemente suficiente), puede ver todos los diferentes grupos y ver cuáles se están acabando.

2

Probablemente se está quedando sin espacio para la Generación Permanente. Compruebe si el seguimiento de la pila contiene algo así como java.lang.OutOfMemoryError: PermGen

puede aumentar el espacio para esta generación con este parámetro para la JVM: -XX: MaxPermSize = 128m

Los objetos en la generación permanente no se consideran durante la recolección de basura. Eche un vistazo a this page from sun para obtener más información sobre la recolección de basura y las diferentes generaciones de objetos en la JVM.

Cuestiones relacionadas