2012-06-07 4 views
7

Ich benutze Tomcat7, der Server ist ziemlich mächtig, 8 GB RAM 8-Core.Tomcat Speicherverwaltung

tomcat taking a LOT of memory for nothing ?

Mein Problem ist, dass der RES Speicher höher und höher wird Geting, bis der Server einfach nicht mehr reagiert, nicht einmal telefonieren OnOutOfMemoryError.

Tomcat-Konfiguration:

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

Speicher Informationen:

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 

Der Speicher verwendet von Tomcat sieht nicht so hoch im Vergleich zu den Top-Befehl.

app memory graph

Ich hatte auch java.net.SocketException: No buffer space available wenn SMTP-Server zu verbinden versuchen, oder wenn sie versuchen, auf Facebook-Servern zu verbinden.

Ich benutze Hibernate, mit c3p0 Verbindungspool mit dieser Konfiguration:

 <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> 

ich nichts ... hat jemand eine Andeutung davon, wo ich soll suchen finden kann?

Danke!

[UPDATE 1] Heapdump:

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] Die Ausgabe von Log-Dateien: ****

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

Ich benutze eine ServletContextListener in meiner Anwendung Controller instanziiert und einen Verweis mit event.getServletContext().setAttribute zu halten. Diese Controller laden Konfigurationen und Übersetzungen (das 88Mb in Perm).

dann die Datenbank zu verwenden, die ich benutze:

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. dies die Quelle eines Lecks sein könnte?
  2. Warum nicht manuelle Transaktion/Sitzung verwenden, und wie würden Sie dann tun?
+0

Wenn der Server nicht mehr reagiert, sollten Sie auch einen Thread-Dump erhalten (siehe http://wiki.apache.org) /tomcat/HowTo#How_do_I_obtain_a_thread_dump_of_my_running_webapp_.3F) um zu sehen, was Ihre JVM tatsächlich macht. Können Sie auch Ihre -Konfiguration (en) von server.xml posten, uns über alle in Ihrem DBCP aktivierten Funktionen für abgebrochene Verbindungen informieren und uns mitteilen, wie hoch die Dateizugriffsgrenze für Ihren JVM-Prozess ist? Alles in den Protokollen - vor allem logs/catalina.out (oder wo auch immer stdout)? –

+0

Update 2: server.xml. OK, danke, ich werde versuchen, das nächste Mal jstack es blockiert! Auf meiner MySQL-Prozessliste sehe ich eine kostenpflichtige Verbindung, nichts komisches. In den Protokollen habe ich es in Update 3 –

+0

Ihre Anwendung verwendet viele HQL? Hibernate Annotationen oder XML? Ist der HQL-Abschluss statisch? – ssedano

Antwort

14

Versuchen mit diesem Parameter:

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

auch mit niedrigerem Start Speicher versuchen Parameter -Xms.

dann können Sie den Dump überprüfen, um festzustellen, ob das Problem Objektzuordnung war.

Während laufender Versuch

jps 

Das wird ausgegeben alle Java-Prozesse, können sagen, Tomcat ist PID 4444:

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

Und

jhat heapdump 

Wenn Sie nicht genügend Arbeitsspeicher, während laufen Ausführen von jhat fügen Sie einfach mehr Speicher hinzu. Von dort aus können Sie den Heap Ihrer Anwendung prüfen.

Eine weitere Möglichkeit besteht darin, Hibernate-Statistiken zu aktivieren, um zu überprüfen, dass Sie keine weiteren Objekte abrufen. Obwohl es aussieht wie eine volle Müllabfuhr, sollte jede Stunde kein Problem sein (Raum dafür besser dort).

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

Und mit GCViewer zum Beispiel in jedem Raum des Speichers einen Blick (ternured, eden, Überlebende, Perm).

Ein weiteres praktisches Werkzeug:

jstack 4444 > stack.txt 

, dass eine vollständige Stapelüberwachung von jedem Thread abruft innerhalb des Java-Prozess mit pid 4444.

Beachten Sie laufen, die Sie Privilegien benötigen, wenn Sie Tomcat begann als root oder ein anderer Benutzer.

wird nicht Prozess ausgeben, die Sie keine Berechtigungen haben, daher können Sie keine Verbindung herstellen.

Da ich nicht weiß, was Ihre Anwendung ist (und daher kenne ich seine Anforderungen nicht) 3 Millionen Instanzen sieht aus wie eine Menge.

Mit Hibernate statistics können Sie sehen, welche Klassen Sie am häufigsten instanziieren.

Dann tunning die Proportionen Ihrer eden and ternured Mülltrennung kann effizienter sein.

Neu instanziierte Objekte gehen zu eden. Wenn es einen kleinen GC füllt, löst es aus. Was nicht gelöscht wird, wird in einen Überlebendenbereich verschoben. Wenn dies voll ist, wird es zu langsam gemacht. Volles GC wird entstehen, wenn die Ternurierung voll ist.

In diesem Bild (das ungenau ist) habe ich String beiseite gelassen, die interniert werden und Speicher gemappte Dateien (die nicht in Heap sind). Sehen Sie sich an, welche Klassen Sie am häufigsten erstellen. Intensive Verwendung von String kann dazu führen, schnell zu füllen Dauerwelle.

Ich denke, Sie tun dies, aber verwenden Sie eine verwaltete Session-Factory, wie Spring (wenn in Ihrem Stapel) und manuelle Verwaltung von Transaktionen und Sitzungen zu vermeiden.

Bedenken Sie, dass Objekte im GC gelöscht werden, wenn kein Objekt darauf verweist. Solange ein Objekt in Ihrer Anwendung erreichbar ist, bleibt das Objekt erhalten.

Wenn Ihr ServletContextListener Controller instanziiert und im Ereignis getServletContext gespeichert wird. Stellen Sie sicher, dass Sie die Referenz anschließend vollständig entfernen. Wenn Sie einen Verweis beibehalten, werden die Objekte nicht gelöscht, da sie immer noch erreichbar sind.

Wenn Sie Ihre eigenen Transaktionen und Sitzungen verwalten (was in Ordnung ist, wenn Sie kein Framework verwenden können), müssen Sie sich mit Codewartung und Bugs beschäftigen, die zum Beispiel Spring-tx gelöst und verbessert haben.

Ich persönlich würde FOSS nutzen. Aber natürlich kann man den Stack nicht vergrößern. Wenn Sie Hibernate verwenden, würde ich Spring-orm und Spring-tx betrachten, um Transaktionen und Sitzung zu verwalten. Werfen Sie auch einen Blick auf Hibernate patter Open Session In View.

+0

Danke, ich werde das hinzufügen und überprüfen Heap Dump (ich überprüfte es von Javamelody, es sah gut aus und entsprach dem Graphen: Heap-Klassen: 4.367, Instanzen: 3.376.160, Kilo-Bytes: 372.020) –

+0

Danke, da mein Server normal läuft, gibt JStack jetzt "nutzlose" Informationen, aber ich werde es tun, wenn einfrieren passiert wieder mit einem Skript –

+0

Aber wenn Hibernate Objekte leckte, würde es nicht im "verwendeten Speicher" der Anwendung bleiben (wie: org.hibernate.hql.ast.tree.Node \t 240,128 Instanzen 11MB)? –

2

Ich würde auch empfehlen, dass Sie Visual VM 1.3.3 herunterladen, alle Plugins installieren und es an die Tomcat-PID anhängen, damit Sie sehen können, was in Echtzeit passiert. Warum auf einen Thread Dump warten? Es teilt Ihnen auch CPU, Threads, alle Heap-Generationen mit, welche Objekte den meisten Speicher verbrauchen usw.

+0

Dazu muss er die Startparameter hinzufügen. Auch jmap wird bei Bedarf gespeichert. jvisualvm ist fast so gut und kein Download. -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port = 9004 -Dcom.sun.management.jmxremote.ssl = false -Dcom.sun.management.jmxremote.authenticate = false – ssedano

+0

Ich habe versucht YourKit (was Visual VM ähnelt), hat mir leider nicht geholfen, das Problem zu lösen (ich könnte es nur in der Entwicklungsumgebung verwenden), gibt es eine Möglichkeit, es in Produktionsserver zu stecken? –

+0

Danke ssedano aber es bedeutet, dass Sie einen JMX-Port als öffentliche öffnen, was ich mir nicht vorstellen kann –