2008-10-20 19 views
5

Jestem programistą C++ i bawię się z java po znalezieniu JPA, który dla kilku moich obecnych aplikacji jest wysyłany przez boga. Nie dotykałem java od czasów uniwersytetu i mam problem z wyczerpaniem przestrzeni sterty. Używam poniższego kodu jako głównej części niezbyt poważnego testu jdbc/jpa/lucene, ale wciąż otrzymuję losowe wyjątki OutOfMemory.Zarządzanie pamięcią 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(); 

nie będę pisać wszystko createDocument ale robi to wystąpienie nowego org.apache.lucene.document.Document i dodaje pól poprzez dodatek (nowe pole ...) itd. Istnieje około 50 pola w sumie i większość to krótkie ciągi znaków (< 32 znaki).

W mojej nowości jest coś zupełnie głupiego, co robię (lub nie), co spowoduje, że rzeczy nie będą GC?

Czy istnieją najlepsze praktyki dotyczące zarządzania pamięcią w języku Java i łaskotania GC?

Odpowiedz

3

Nie widzę niczego oczywistego nie na miejscu. Jeśli pracujesz z bardzo dużą bazą danych, możesz spróbować zwiększyć rozmiar sterty przy użyciu opcji -Xmx n w swoim wywołaniu maszyny JVM. Zwykle nie jest to najlepsze rozwiązanie - zrób to tylko wtedy, gdy wiesz, że twój zestaw roboczy jest większy niż domyślny rozmiar sterty.

Czy używasz złożonych struktur danych? Jeśli masz kołowe odwołania między obiektami, możesz zapobiegać czyszczeniu nieosiągalnych obiektów. Jeśli masz ręcznie zapisane struktury danych, upewnij się, że jawnie usuwane są odwołania do obiektów, które zostały usunięte, zamiast robić coś w rodzaju zmniejszania zmiennej wielkości.

+1

GC nie ma problemów z odwołaniami cyklicznymi, obiekty będą nadal usuwane. Nie jestem pewien, czy rozumiem, co masz na myśli, przez jawne odejście od odniesień do obiektów. Jak inaczej mógłbyś je usunąć? – Robin

+0

Innym sposobem ich usunięcia jest wyjście z zakresu. Jawnie ustawienie odniesień do wartości null dotyczy kombinacji obiektów długich i długich, gdzie odniesienie do obiektu będzie przechowywane w pamięci przez długi czas. – gnud

0

Ile elementów jest w zestawie wyników? Jeśli jest wystarczająco dużo zapisów, to zużyjesz całą swoją pamięć, ponieważ nie ma w tym przypadku żadnych śmieci, ponieważ robisz addDocument do pisarza, który będzie zawierał odniesienia do wszystkich twoich dokumentów.

2

Cóż ...

Wieloletnie doświadczenie z Java i baz danych (an example post PostgresSQL różnice mysql oracle>) nauczyło mnie, że sterowniki JDBC używamy w tej pracy robi często mają problemy.

Mam jeden kawałek kodu, który musi pozostać podłączony do bazy danych 24/7 iz powodu wycieku pamięci sterownika JVM zawsze dusi się w pewnym momencie. Napisałem więc kod, aby wychwycić określony wyjątek, a następnie podjąć coraz bardziej drastyczne działania, w tym przerwanie połączenia i ponowne podłączenie, a nawet ponowne uruchomienie maszyny wirtualnej w rozpaczliwej sytuacji, nic nie działa, aby usunąć tę okoliczność. Cóż za PAIN musiał napisać, ale działało, dopóki dostawca DBMS nie wyszedł z nowym sterownikiem JDBC, który nie spowodował problemu ... Właśnie opuściłem kod, na wszelki wypadek!

... Więc może to być nic, co robisz.

Pamiętaj, że wywoływanie "śmieciarza" było jedną ze strategii, których używałem, ale dane pokazały, że rzadko pomagała.

Ponadto może nie być jasne, ale ResultSets utrzymuje ciągłe połączenie z samym silnikiem bazy danych, w wielu przypadkach (chyba że wyraźnie określono inaczej) dwukierunkowo, nawet jeśli tylko czytasz. A niektóre sterowniki JDBC pozwalają zapytać o połączenie jednokierunkowe, ale kłamać i zwracać dwukierunkowe! Strzeż się tego!

Dobra praktyka polega na rozładowywaniu obiektów ResultSet na inne obiekty w celu przechowywania wartości i jak najszybszego upuszczania obiektów ResultSet.

Powodzenia. RTIII

0

Java utrzymuje kilka różnych pul pamięci i wyczerpanie któregokolwiek z nich może powodować przerażający wyjątek OutOfMermoryException. Problemy z przydzielaniem pamięci przez system operacyjny mogą być również wyświetlane jako OOM.

Powinieneś zobaczyć szczegółowy ślad stosu - lub prawdopodobnie plik zrzutu błędu w katalogu aplikacji - który może dostarczyć dalszych wskazówek na temat problemu.

Jeśli używasz przyzwoitego profilera - JVisualVM, który jest dostarczany z najnowszą wersją JDK Sun Java 6, prawdopodobnie jest wystarczający - możesz obejrzeć wszystkie różne pule i zobaczyć, które z nich się wyczerpują.

2

Prawdopodobnie brakuje miejsca dla Stałego Pokolenia. Sprawdź, czy ślad stosu zawiera coś podobnego java.lang.OutOfMemoryError: PermGen

można zwiększyć przestrzeń dla tego pokolenia z tego parametru dla JVM: -XX: MaxPermSize = 128m

Obiekty w stałej generacji nie są brane pod uwagę podczas zbierania śmieci. Aby uzyskać więcej informacji na temat usuwania śmieci i różnych generacji obiektów w JVM, zobacz: this page from sun.