2008-10-20 18 views
5

Ich bin ein C++ Programmierer und ich spiele herum mit Java, nachdem ich JPA gefunden habe, das für einige meiner gegenwärtigen Anwendungen ein Gott sende. Ich habe Java seit der Universität nicht berührt, und ich habe ein Problem, aus dem Heap-Raum zu laufen. Ich benutze den Code unten als Hauptteil eines nicht-sehr ernsten Tests von jdbc/jpa/lucene, aber ich bekomme weiterhin zufällige OutOfMemory-Ausnahmen.Java-Speicherverwaltung

 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(); 

Ich werde nicht alle create posten, aber alle es tut, ist eine neue org.apache.lucene.document.Document instanziiert und fügt Felder über add (neues Feld ...) usw. Es gibt etwa 50 Felder insgesamt und die meisten sind kurze Zeichenfolgen (< 32 Zeichen) in der Länge.

In meiner Newby-Ness gibt es etwas völlig Dummes, das ich mache (oder nicht), dass Dinge nicht GC'd sein würde?

Gibt es Best Practices in Bezug auf Java Memory Management und kitzeln die GC?

Antwort

3

Ich sehe nichts offensichtlich fehl am Platz. Wenn Sie mit einer sehr großen Datenbank arbeiten, können Sie versuchen, die Größe Ihres Heapspeichers mithilfe der Option -Xmx n in Ihrem JVM-Aufruf zu erhöhen. Dies ist normalerweise nicht die beste Lösung - tun Sie dies nur, wenn Sie wissen, dass die Größe Ihres Arbeitssatzes tatsächlich größer ist als die Standardgröße des Heapspeichers.

Verwenden Sie komplexe Datenstrukturen? Wenn Sie Zirkelverweise zwischen Objekten haben, verhindern Sie möglicherweise, dass der Garbage Collector nicht erreichbare Objekte bereinigt. Wenn Sie handgeschriebene Datenstrukturen haben, stellen Sie sicher, dass Sie Verweise auf Objekte, die entfernt werden, explizit aufheben, anstatt z. B. eine Größenvariable zu dekrementieren.

+1

GC hat keine Probleme mit kreisförmigen Referenzen, Objekte werden weiterhin entfernt. Ich bin mir nicht sicher, ob ich verstehe, was Sie meinen, indem Sie Referenzen auf Objekte explizit auf Null setzen. Wie sonst würden Sie sie entfernen? – Robin

+0

Die andere Möglichkeit, sie zu entfernen, besteht darin, sie außer Reichweite zu lassen. Das explizite Festlegen von Verweisen auf NULL bezieht sich auf die Kombination von humongous Objekten und langen Schleifen, bei denen die Objektreferenz lange im Speicher verbleibt. – gnud

0

Wie viele Artikel sind in Ihrem Ergebnissatz enthalten? Wenn genügend Datensätze vorhanden sind, wird der gesamte Speicher belegt, da in diesem Fall nichts Müll gesammelt wird, da Sie dem Writer ein addDocument hinzufügen, das einen Verweis auf alle von Ihnen erstellten Dokumente enthält. Nun

2

...

Lange Erfahrung mit Java und Datenbanken (an example post PostgresSQL mysql oracle Unterschiede>) hat mich gelehrt, dass die JDBC-Treiber wir dabei, diese Arbeit häufig Probleme haben, verwenden.

Ich habe einen Codeabschnitt, der rund um die Uhr mit einer Datenbank verbunden bleiben muss, und wegen eines Speicherlecks des Treibers würde die JVM immer irgendwann ersticken. Also habe ich Code geschrieben, um die spezielle Ausnahme zu fangen und dann immer drastischer zu handeln, einschließlich das Abwerfen der Verbindung und das erneute Verbinden und sogar Neustarten der JVM in einem verzweifelten, nichts funktioniert, um das Problem zu beheben. Was für ein SCHMERZ ich haben musste, um es zu schreiben, aber es funktionierte, bis der DBMS-Hersteller einen neuen JDBC-Treiber herausbrachte, der das Problem nicht verursachte ... Ich habe den Code nur für den Fall gelassen!

... Also könnte es nichts sein, was Sie tun.

Beachten Sie, dass das Aufrufen des Garbage Collector eine der Strategien war, die ich verwendete, aber Metriken zeigten, dass es selten half.

Darüber hinaus ist es möglicherweise nicht klar, aber ResultSets pflegen eine laufende Verbindung mit der Datenbank-Engine selbst, in vielen Fällen (sofern nicht explizit anders festgelegt) bidirektionale, auch wenn Sie gerade lesen. Und bei einigen JDBC-Treibern können Sie nach einer monodirektionalen Verbindung fragen, aber lügen und eine bidirektionale zurückgeben! Vorsicht mit diesem!

Es ist also eine gute Methode, Ihre ResultSet-Objekte in andere Objekte zu entladen, um die Werte zu speichern und die ResultSet-Objekte selbst so schnell wie möglich zu löschen.

Viel Glück. RTIII

0

Java unterhält mehrere verschiedene Speicherpools und das Auslaufen eines beliebigen von ihnen kann die gefürchtete OutOfMermoryException verursachen. Probleme beim Zuweisen von Speicher durch das Betriebssystem können auch als OOM auftreten.

Sie sollten eine detaillierte Stack-Trace - oder möglicherweise eine Fehler-Dump-Datei im Verzeichnis der Anwendung - sehen, die weitere Hinweise auf das Problem geben kann.

Wenn Sie einen anständigen Profiler verwenden - JVisualVM, das mit den letzten Sun Java 6 JDKs ausgeliefert wird, ist wahrscheinlich ausreichend - können Sie alle verschiedenen Pools beobachten und sehen, welche gerade auslaufen.

2

Wahrscheinlich haben Sie keinen Platz mehr für die Permanent Generation. Überprüfen Sie, ob Ihr Stack-Trace enthält so etwas wie java.lang.OutOfMemoryError: PermGen

Sie können mit diesem Parameter für die JVM den Raum für diese Generation erhöhen: -XX: MaxPermSize = 128m

Objekte in der ständigen Generation werden während der Speicherbereinigung nicht berücksichtigt. Werfen Sie einen Blick auf this page from sun, um mehr über die Garbage Collection und die verschiedenen Generationen von Objekten in der JVM zu erfahren.