2012-06-07 14 views
7

Używam Tomcat7, serwer jest dość potężny, 8-bitowy RAM 8-rdzeniowy.Zarządzanie pamięcią Tomcat

tomcat taking a LOT of memory for nothing ?

Moim problemem jest to, że pamięć RES jest czuło się wyżej i wyżej, aż serwer po prostu nie reaguje już nawet nie nazywając OnOutOfMemoryError.

konfiguracja Tomcat:

-Xms1024M 
-Xmx2048M 
-XX:PermSize=256m 
-XX:MaxPermSize=512m 
-XX:+UseConcMarkSweepGC 
-XX:OnOutOfMemoryError='/var/tomcat/conf/restart_tomcat.sh' 

informacje pamięci:

Memory:  Non heap memory = 106 Mb (Perm Gen, Code Cache), 
Loaded classes = 14,055, 
Garbage collection time = 47,608 ms, 
Process cpu time = 4,296,860 ms, 
Committed virtual memory = 6,910 Mb, 
Free physical memory = 4,906 Mb, 
Total physical memory = 8,192 Mb, 
Free swap space = 26,079 Mb, 
Total swap space = 26,079 Mb 
Perm Gen memory: 88 Mb/512 Mb ++++++++++++ 
Free disk space: 89,341 Mb 

Pamięć używana przez Tomcat nie wygląda, że ​​wysokie w porównaniu do górnej polecenia.

app memory graph

Miałem również java.net.SocketException: No buffer space available gdy próbuje połączyć się z serwerem SMTP lub gdy próbuje połączyć się z serwerami Facebooka.

używam hibernacji, z puli połączeń C3P0 z tej konfiguracji:

 <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> 
     <property name="hibernate.connection.url">jdbc:mysql://urldb/schema?autoReconnect=true</property> 
     <property name="hibernate.connection.username">username</property> 
     <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> 
     <property name="hibernate.connection.password"></property> 
     <property name="connection.characterEncoding">UTF-8</property> 

     <property name="hibernate.c3p0.acquire_increment">1</property> 
     <property name="hibernate.c3p0.idle_test_period">300</property> 
     <property name="hibernate.c3p0.timeout">5000</property> 
     <property name="hibernate.c3p0.max_size">50</property> 
     <property name="hibernate.c3p0.min_size">1</property> 
     <property name="hibernate.c3p0.max_statement">0</property> 
     <property name="hibernate.c3p0.preferredTestQuery">select 1;</property> 
     <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> 

nie mogłem znaleźć nic ... czy ktoś ma podpowiedź, gdzie należy szukać?

Dzięki!

[UPDATE 1] zrzut stosu:

HEAP HISTOGRAM : 

class [C         269780 34210054 
class [B         5600 33836661 
class java.util.HashMap$Entry    221872 6212416 
class [Ljava.util.HashMap$Entry;   23797 6032056 
class java.lang.String      271170 5423400 
class org.hibernate.hql.ast.tree.Node  103588 4972224 
class net.bull.javamelody.CounterRequest 28809 2996136 
class org.hibernate.hql.ast.tree.IdentNode 23461 2205334 
class java.lang.Class      14677 2113488 
class org.hibernate.hql.ast.tree.DotNode 13045 1852390 
class [Ljava.lang.String;     48506 1335600 
class [Ljava.lang.Object;     12997 1317016 


Instance Counts for All Classes (excluding platform) : 

103588 instances of class org.hibernate.hql.ast.tree.Node 
33366 instances of class antlr.ANTLRHashString 
28809 instances of class net.bull.javamelody.CounterRequest 
24436 instances of class org.apache.tomcat.util.buf.ByteChunk 
23461 instances of class org.hibernate.hql.ast.tree.IdentNode 
22781 instances of class org.apache.tomcat.util.buf.CharChunk 
22331 instances of class org.apache.tomcat.util.buf.MessageBytes 
13045 instances of class org.hibernate.hql.ast.tree.DotNode 
10024 instances of class net.bull.javamelody.JRobin 
9084 instances of class org.apache.catalina.loader.ResourceEntry 
7931 instances of class org.hibernate.hql.ast.tree.SqlNode 

[UPDATE 2] server.xml:

<Connector port="8080" protocol="HTTP/1.1" 
       connectionTimeout="20000" 
       redirectPort="8443" 
       URIEncoding="UTF-8" 
       maxThreads="150" 
       minSpareThreads="25" 
       maxSpareThreads="75" 
       enableLookups="false" 
       acceptCount="1024" 
       server="unknown" 
       address="public_ip" 
    /> 

**** [UPDATE 3] Wyjście z plików dziennika: ****

2012-06-04 06:18:24,152 [http-bio-ip-8080-exec-3500] ERROR org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/api].[Jersey REST Service]- Servlet.ser 
vice() for servlet [Jersey REST Service] in context with path [/socialapi] threw exception 
java.net.SocketTimeoutException: Read timed out 

    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(SocketInputStream.java:129) 
    at org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:532) 
    at org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:501) 
    at org.apache.coyote.http11.InternalInputBuffer$InputStreamInputBuffer.doRead(InternalInputBuffer.java:563) 
    at org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:118) 
    at org.apache.coyote.http11.AbstractInputBuffer.doRead(AbstractInputBuffer.java:326) 
    at org.apache.coyote.Request.doRead(Request.java:422) 

[UPDATE 4] ServletContext

Używam ServletContextListener w mojej aplikacji do administrowania kontrolerami i utrzymywania referencji z event.getServletContext().setAttribute. Sterowniki ładują konfiguracje i tłumaczenia (88 Mb w Perm).

Następnie do korzystania z bazy danych używam:

SessionFactory sf = dbManager.getSessionFactory(DatabaseManager.DB_KEY_DEFAULT); 
Session session = sf.openSession(); 
Transaction tx = null; 

try { 
    tx = session.beginTransaction(); 

    //Do stuuf 

    tx.commit(); 

} catch (Exception e){ 
    //Do something 
} finally { 
    session.close(); 
} 
  1. może to być źródłem przecieku?
  2. Dlaczego nie używać transakcji/sesji ręcznej i jak by to zrobić?
+0

Gdy serwer przestanie odpowiadać, powinieneś również uzyskać zrzut wątku (zobacz http://wiki.apache.org /tomcat/HowTo#How_do_I_obtain_a_thread_dump_of_my_running_webapp_.3F), aby zobaczyć, co faktycznie robi maszyna JVM. Czy możesz również opublikować swoją konfigurację z serwera server.xml, poinformować nas o wszelkich "porzuconych połączeniach" włączonych w twoim DBCP, a także powiedzieć nam, jaki jest limit obsługi pliku dla twojego procesu JVM? Coś w dziennikach - w szczególności dzienniki/catalina.out (lub gdziekolwiek trafi stdout)? –

+0

Aktualizacja 2: server.xml. OK, dzięki, spróbuję jstack następnym razem, gdy się zablokuje! na mojej liście procesorów mysql widzę połączenie oczekujące, nic dziwnego. W dziennikach umieściłem go w aktualizacji 3 –

+0

Twoja aplikacja używa wielu HQL? Adnotacje hibernacji lub xml? Czy finał HQL jest statyczny? – ssedano

Odpowiedz

14

spróbuj tego parametru:

+XX:+HeapDumpOnOutOfMemoryError -XX:+HeapDumpPath=dump.log 

spróbować również z niższym pamięci Parametry startowe -Xms.

następnie można sprawdzić zrzut, aby sprawdzić, czy problem dotyczy przydzielania obiektów.

Podczas jazdy spróbować

jps 

To wyświetli wszystkie procesy Java, powiedzmy Tomcat jest PID 4444:

jmap -dump:format=b,file=heapdump 4444 

I

jhat heapdump 

Jeśli zabraknie czas pamięci wykonanie jhat wystarczy dodać więcej pamięci. Stamtąd możesz sprawdzić stertę swojej aplikacji.

Innym sposobem jest włączenie statystyk hibernacji w celu sprawdzenia, czy nie pobierasz więcej obiektów. Chociaż wygląda na to, że co godzinę nabieżemy na śmietnik, nie powinno to stanowić problemu (miejsce na lepsze).

-verbose:gc -Xloggc:/opt/tomcat/logs/gc.out -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 

I z GCViewer na przykład spojrzeć na każdej przestrzeni pamięci (ternured, Eden, którzy przeżyli, Perm).

Innym przydatnym narzędziem:

jstack 4444 > stack.txt 

To będzie odzyskać pełną ślad stosu każdego wątku działa wewnątrz procesu java z PID 4444.

pamiętać, że trzeba przywileje jeśli rozpoczął Tomcat jako root lub inny użytkownik.

jps 

nie będzie wyprowadzać procesu, do którego nie masz uprawnień, dlatego nie możesz się z nim połączyć.

Ponieważ nie wiem, o czym jest twoja aplikacja (a więc nie znam jej wymagań), 3 miliony instancji wygląda na bardzo wiele.

Dzięki Hibernate statistics możesz zobaczyć, które klasy tworzysz najbardziej.

Wówczas dostrojenie proporcji ponownej oceny śmieci może być bardziej efektywne.

Nowo utworzone obiekty trafiają do Eden. Kiedy się zapełni, uruchamia się mały gc. To, co nie zostało usunięte, trafia do przestrzeni, która przeżyła. Kiedy to się zapełni, idzie do zarodka. Pełne gc pojawi się, gdy potęga jest pełna.

Na tym zdjęciu (które jest niedokładne) zostawiłem na boku String, które zostaną internowane i pliki mapowane w pamięci (które nie są w sterty). Sprawdź, na których klasach tworzysz najwięcej. Intensywne użycie String może spowodować szybkie zapełnienie perm.

Domyślam się, że tak, ale używaj fabryki zarządzanych sesji, takich jak Spring (jeśli masz w stosie) i unikaj ręcznego zarządzania transakcjami i sesjami.

Należy pamiętać, że obiekty są usuwane z GC, gdy żaden obiekt się do nich nie odnosi. Dopóki obiekt jest osiągalny w aplikacji, obiekt pozostaje.

Jeśli twój ServletContextListener stworzył kontrolery i są przechowywane w zdarzeniu getServletContext. Upewnij się, że całkowicie usuniesz referencję, jeśli zachowasz odniesienie, obiekty nie zostaną usunięte, ponieważ są nadal dostępne.

Jeśli zarządzasz własnymi transakcjami i sesją (co jest w porządku, jeśli nie możesz korzystać z frameworka), musisz poradzić sobie z utrzymaniem kodu i błędami, które na przykład rozwiązano i poprawiono na przykład na Spring-tx.

Osobiście skorzystam z FOSS. Ale czasami nie można powiększyć stosu.

Jeśli korzystasz z usługi Hibernate, powinienem przejrzeć Spring-orm i Spring-tx, aby zarządzać transakcjami i sesją. Zobacz także Hibernate patter Open Session In View.

+0

dzięki, dodam to i sprawdzam stertę sterty (sprawdziłem to od javamelody, wyglądało dobrze i odpowiadało wykresowi: Klasy sterty: 4,367, Wystąpienia: 3,376,160, Kilo-Bytes: 372,020) –

+0

Dzięki, jak mój serwer działa normalnie teraz jstack podaje "bezużyteczne" informacje, ale zrobię to, jeśli wystąpi zamrożenie ponownie ze skryptem –

+0

Ale jeśli hibernacja wyciekała z obiektów, czy nie pozostawałaby w "używanej pamięci" aplikacji (np .: org.hibernate.hql.ast.tree.Node \t 240,128 Instances 11MB)? –

2

Zalecam również pobranie Visual VM 1.3.3, zainstalowanie wszystkich wtyczek i dołączenie go do PID Tomcat, aby można było zobaczyć, co dzieje się w czasie rzeczywistym. Po co czekać na zrzut wątku? Powie Ci również procesor, wątki, wszystkie generacje sterty, które obiekty zużywają najwięcej pamięci, itp.

+0

, aby to zrobić, będzie musiał dodać parametry początkowe. Również jmap zrzuca na żądanie. jvisualvm jest prawie tak dobry i bez pobierania. -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port = 9004 -Dcom.sun.management.jmxremote.ssl = false -Dcom.sun.management.jmxremote.authenticate = false – ssedano

+0

Próbowałem YourKit (który wygląda podobnie do Visual VM), niestety nie pomógł mi rozwiązać problemu (mogłem go używać tylko w środowisku programistycznym), czy istnieje sposób na podłączenie go do serwerów produkcyjnych? –

+0

Dziękuję ssedano, ale oznacza to, że otwierasz port JMX jako publiczny, co jest czymś, czego nie mogę sobie wyobrazić –