java Tomcat内存管理

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10933291/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 03:08:17  来源:igfitidea点击:

Tomcat memory management

javahibernatetomcattomcat7

提问by Camille R

I'm running Tomcat7, the server is quite powerful, 8 GB RAM 8-core.

我正在运行 Tomcat7,服务器非常强大,8 GB RAM 8 核。

tomcat taking a LOT of memory for nothing ?

tomcat 白白占用了大量内存?

My problem is that the RES memory is geting higher and higher, until the server just doesn't respond anymore, not even calling OnOutOfMemoryError.

我的问题是 RES 内存越来越高,直到服务器不再响应,甚至不调用 OnOutOfMemoryError。

Tomcat configuration :

Tomcat配置:

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

Memory informations :

内存信息:

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 

The memory used by Tomcat doesn't look that high compared to the top command.

与 top 命令相比,Tomcat 使用的内存看起来并不高。

app memory graph

应用内存图

I also had java.net.SocketException: No buffer space availablewhen trying to connect to SMTP server or when trying to connect to facebook servers.

java.net.SocketException: No buffer space available在尝试连接到 SMTP 服务器或尝试连接到 Facebook 服务器时也遇到过。

I use Hibernate, with c3p0 connection pool with this configuration :

我使用 Hibernate 和带有以下配置的 c3p0 连接池:

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

I couldn't find anything... does someone have an hint of where I should be looking for ?

我找不到任何东西......有人暗示我应该在哪里寻找吗?

Thanks!

谢谢!

[UPDATE 1]HEAP DUMP :

[更新 1] 堆转储:

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 :

[更新 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] Output from log files : ****

****[更新 3] 日志文件的输出:****

    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

[更新 4] ServletContext

I use a ServletContextListenerin my application to instanciate controllers and keep a reference with event.getServletContext().setAttribute. Those controllers loads configurations and translations (the 88Mb in Perm).

ServletContextListener在我的应用程序中使用 a来实例化控制器并使用event.getServletContext().setAttribute. 这些控制器加载配置和转换(Perm 中的 88Mb)。

Then to use the database i use :

然后使用我使用的数据库:

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. Could this be the source of a leak ?
  2. Why not to use Manual transaction/session, and how would you do then ?
  1. 这可能是泄漏的来源吗?
  2. 为什么不使用手动事务/会话,然后你会怎么做?

回答by ssedano

Try with this parameter:

试试这个参数:

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

Also try with lower start memory parameters -Xms.

也尝试使用较低的启动内存参数-Xms

then you can inspect the dump to see if the problem was object allocation.

然后您可以检查转储以查看问题是否出在对象分配上。

While running try

在运行时尝试

jps

That will output all java processes, lets say Tomcatis PID4444:

这将输出所有java进程,假设TomcatPID4444:

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

And

jhat heapdump

If you run out of memory while executing jhat just add more memory. From there you can inspect the heap of your application.

如果在执行 jhat 时内存不足,只需添加更多内存。从那里您可以检查应用程序的堆。

Another way to go is to enable Hibernate statistics to check that you are not retrieving more objects. Although it looks like a full garbage collection every hour should not be a problem (room for do it better there).

另一种方法是启用 Hibernate 统计以检查您是否没有检索更多对象。虽然看起来每小时进行一次完整的垃圾收集应该不成问题(在那里做得更好)。

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

And with GCViewer for example take a look at every space of memory (ternured, eden, survivors, perm).

例如,使用 GCViewer 查看内存的每个空间(ternured、eden、survivors、perm)。

Another handy tool:

另一个方便的工具:

jstack 4444 > stack.txt

That will retrieve a full stack trace of every thread running inside the java process with pid 4444.

这将检索在 pid 为 4444 的 java 进程中运行的每个线程的完整堆栈跟踪。

Bear in mind that you need privileges if you started Tomcatas root or another user.

请记住,如果您Tomcat以 root 或其他用户身份启动,则需要特权。

jps

won't output process which you have no privileges, therefore you cannot connect to it.

不会输出您没有权限的进程,因此您无法连接到它。

Since I don't know what your application is about (and therefore I don't know its requirements) 3 million instances looks like a lot.

由于我不知道您的应用程序是关于什么的(因此我不知道它的要求)300 万个实例看起来很多。

With Hibernate statisticsyou can see which classes you instantiate the most.

使用Hibernate statistics您可以查看您实例化最多的类。

Then tunning the proportions of your eden and ternuredgarbage recolection can be more efficient.

然后调整eden and ternured垃圾回收的比例会更有效。

Newly instantiated objects goes to eden. When it fills up a minor gc triggers. What is not deleted goes to a survivor space. When this fills up it goes to ternured. Full gc will arise when ternured is full.

新实例化的对象进入 eden。当它填满一个次要的 gc 触发器时。未删除的内容将进入幸存者空间。当它填满时,它会变成 ternured。当 ternured 已满时,将出现 Full gc。

In this picture (which is inaccurate) I left aside Stringthat become interned and Memory mapped files (that are not in heap). Take a look at which classes you instantiate most. Intensive use of Stringmight lead to quickly fill up perm.

在这张图片(这是不准确的)中,我把String那些成为实习生和内存映射文件(不在堆中)放在一边。看看你最常实例化的类。密集使用String可能会导致烫发迅速填满。

I guess you do so, but use a managed session factory, such as Spring (if in your stack) and avoid manually management of transactions and sessions.

我猜你会这样做,但使用托管会话工厂,例如 Spring(如果在您的堆栈中)并避免手动管理事务和会话。

Keep in mind that objects are deleted in the GC when no object refers to it. So as long as a object is reachable in your application the object remain.

请记住,当没有对象引用它时,对象会在 GC 中被删除。因此,只要在您的应用程序中可以访问对象,该对象就会保持不变。

If your ServletContextListener instantiate controllers and are stored in the event getServletContext. Make sure you completely remove the reference afterwards, if you keep a reference the objects won't be deleted, since they are still reachable.

如果您的 ServletContextListener 实例化控制器并存储在事件 getServletContext 中。确保之后完全删除引用,如果保留引用,则不会删除对象,因为它们仍然可以访问。

If you manage your own transactions and session (which is fine if you cannot use a framework) then you must deal with code maintenance and bugs that Spring-txfor instance has solved and improved.

如果您管理自己的事务和会话(如果您不能使用框架,这很好),那么您必须处理Spring-tx例如已经解决和改进的代码维护和错误。

I personally would take advantage of FOSS. But of course sometime you cannot enlarge the stack.

我个人会利用FOSS. 但当然有时你不能扩大堆栈。

If you are using HibernateI would take a look at Spring-ormand Spring-txto manage transactions and session. Also take a look at Hibernate patter Open Session In View.

如果您正在使用,Hibernate我会查看Spring-ormSpring-tx管理事务和会话。也看看Hibernate patter Open Session In View

回答by duffymo

I'd also recommend that you download Visual VM 1.3.3, install all the plugins, and attach it to the Tomcat PID so you can see what's happening in real time. Why wait for a thread dump? It'll also tell you CPU, threads, all heap generations, which objects consume the most memory, etc.

我还建议您下载 Visual VM 1.3.3,安装所有插件,并将其附加到 Tomcat PID,以便您可以实时查看发生的情况。为什么要等待线程转储?它还会告诉您 CPU、线程、所有堆代、哪些对象消耗最多内存等。