Tomcat修复内存泄漏?

9 浏览
0 Comments

Tomcat修复内存泄漏?

我使用的是6.0.20版本。我在服务器上运行了许多Web应用程序,随着时间的推移,大约3天后,服务器需要重新启动,否则服务器会崩溃并变得无响应。\n我对JVM进行了以下设置:\n

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=c:\tomcat\Websites\private\mydomain\apache-tomcat-6.0.20\logs

\n这为我提供了一个hprof文件,我使用Java VisualVM加载该文件后发现以下问题:\n

byte[] 37,206个实例 | 大小 86,508,978
int[] 540,909个实例 | 大小 55,130,332
char[] 357,847个实例 | 大小 41,690,928

\n列表还在继续,但我如何确定是什么导致了这些问题呢?\n我正在使用New Relic监控JVM,只有一个错误似乎出现了,但它是一个经常发生的错误,org.apache.catalina.connector.ClientAbortException。有可能当用户会话中止时,未关闭任何数据库连接或创建的变量,从而导致它们被遗留下来吗?\n每个Web应用程序都会频繁使用一个函数,不确定这是否与内存泄漏有关:\n

public static String replaceCharacters(String s)
{
    s = s.replaceAll("  ", " ");
    s = s.replaceAll(" ", "_");
    s = s.replaceAll("\351", "e");
    s = s.replaceAll("/", "");
    s = s.replaceAll("--", "-");
    s = s.replaceAll("&", "and");
    s = s.replaceAll("&", "and");
    s = s.replaceAll("__", "_");
    s = s.replaceAll("\\(", "");
    s = s.replaceAll("\\)", "");
    s = s.replaceAll(",", "");
    s = s.replaceAll(":", "");
    s = s.replaceAll("\374", "u");
    s = s.replaceAll("-", "_");
    s = s.replaceAll("\\+", "and");
    s = s.replaceAll("\"", "");
    s = s.replaceAll("\\[", "");
    s = s.replaceAll("\\]", "");
    s = s.replaceAll("\\*", "");
    return s;
}

\n有可能当用户连接中止时,例如用户关闭浏览器或用户离开网站时,所有变量、连接等都被清除/释放,但是GC不应该处理这些吗?\n以下是我的JVM设置:\n

-Dcatalina.base=c:\tomcat\Websites\private\mydomain\apache-tomcat-6.0.20
-Dcatalina.home=c:\tomcat\Websites\private\mydomain\apache-tomcat-6.0.20
-Djava.endorsed.dirs=c:\tomcat\Websites\private\mydomain\apache-tomcat-6.0.20\endorsed
-Djava.io.tmpdir=c:\tomcat\Websites\private\mydomain\apache-tomcat-6.0.20\temp
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=c:\tomcat\Websites\private\mydomain\apache-tomcat-6.0.20\conf\logging.properties
-Dfile.encoding=UTF-8
-Dsun.jnu.encoding=UTF-8
-javaagent:c:\tomcat\Websites\private\mydomain\apache-tomcat-6.0.20\newrelic\newrelic.jar
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=c:\tomcat\Websites\private\mydomain\apache-tomcat-6.0.20\logs
-Dcom.sun.management.jmxremote.port=8086
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false vfprintf
-Xms1024m
-Xmx1536m

\n我有什么遗漏吗?服务器有3GB的内存。\n非常感谢您的帮助 🙂

0
0 Comments

Tomcat Fix Memory Leak?

最近在本地开发环境中启动服务器,并附加分析器(最好使用YourKit)。定期获取堆转储文件,你会发现对象byte[]的增长,并且你可以通过使用这个工具将这些byte[]与泄漏它的应用程序类进行连接,从而帮助你识别代码中的缺陷。

使用Eclipse Memory Analyzer,我可以看到由于ClientAbortExceptions而导致的byte[]实例。这是因为用户在页面完全加载之前离开了网页或站点,因此图片还没有完全下载。

你是指修复ClientAbortException吗?我是否需要扩展每个函数来修复它,还是可以通过在server.xml文件中声明一个类来全局处理断开的请求?

0
0 Comments

我们将所有的项目迁移到了Tomcat 7.0.42,错误已经消失了,我们的网站更加稳定且稍微快了一些,我们使用的内存更少,CPU使用情况也更好一些。

0
0 Comments

Tomcat Fix Memory Leak?

在使用Tomcat时,有一个内存泄漏的问题,但是如何确定是什么原因造成了这个问题呢?你需要使用一个内存分析工具来查看是什么让这些对象仍然可达。选择一个对象,查看是哪个其他对象引用了它...然后沿着链条向后查找,直到找到一个"GC root"或者你认识的一些特定的应用类。

这里有一些关于分析内存快照和内存分析工具的参考资料:

- [如何分析.hprof文件?](https://stackoverflow.com/questions/185893)

- [如何使用visualvm查找内存泄漏](https://stackoverflow.com/questions/9154785)

- [解决OutOfMemoryError-内存分析工具](http://plumbr.eu/blog/solving-outofmemoryerror-memory-profilers)

一旦你确定了原因,你就已经基本上找到了存储泄漏的来源。

那个函数与泄漏没有直接关系。它肯定不会引起泄漏。(它可能会生成大量的垃圾String对象...但这是一个不同的问题。)

我正在使用Java VisualVM来查看堆转储。如果我选择int[],有534,335个实例,如果我选择其中一个实例,它会显示有<500个实例>有一个值,如果我选择其中一个实例,就没有其他信息。我做错了什么吗?

我注意到了与com.mysql.jdbc.NonRegisteringDriver$1.run(NonRegisteringDriver.java:93)相关的废弃连接清理线程,这是否有关?

我想我可能已经发现了一些线索,我使用的是mysql-connector-java-5.1.21-bin.jar,我相信它有一个问题,导致Tomcat无法释放废弃的线程。考虑改用mysql-connector-java-5.1.25-bin.jar。

这肯定是一个合理的解释。尝试一下,看看更换JAR文件是否有帮助。这应该是一个"低风险"的更改。但是,考虑到泄漏对象的数量,我怀疑你发现的不是唯一的重要泄漏。

我将从这里开始,我注意到堆的大小在1GB到1.5GB之间,但是PermGen在55MB到85MB之间,我认为这也需要一些关注,这是否会导致GC几乎不停地运行?你对PermGen的大小有什么建议吗?

我已经移除了mysql-connector-java-5.1.21-bin.jar并替换为mysql-connector-java-5.1.25-bin.jar,将-XX:PermSize=512m和-XX:MaxPermSize=512m添加到JVM设置中,只是想知道是否需要添加-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -XX:+UseConcMarkSweepGC。

除非你遇到了说你的permgen内存不足的OOME异常,否则你不需要调整permgen。除非你在进行热部署,否则permgen的水平应该是稳定的。不要同时更改很多东西...因为如果你这样做,你将无法弄清楚到底是什么产生了差异。调整GC参数不会解决存储泄漏的问题。请不要改变它们。

"PermGen在55MB到85MB之间,...这是否会导致GC几乎不停地运行?" 可能不会,但这取决于实际分配permgen的是什么。(热部署?)

谢谢你的建议,我最好移除-XX:PermSize=512m和-XX:MaxPermSize=512m这些行吗?我可以看到堆在300MB到600MB之间波动,显示内存正在被回收,这是一件好事。你知道线程在多长时间后被清理吗?我显示有6个废弃的连接清理线程,加上附加监听器显示了18分钟并且还在增加。

让我们在聊天中继续这个讨论。

经过16小时的运行时间,我可以看到总加载的类为8,118,比昨天显著增加,而总卸载的类为68。堆现在的平均值在350MB到700MB之间,而PermGen增加了17MB。如果我点击一个生成PDF的函数,总加载数现在为8,536,而总卸载数仍然为68。如果我关闭PDF窗口,总加载和卸载的类仍然保持在较高的水平,执行完毕后类不应该卸载吗?

当类加载器变得不可达时,类将被卸载。但只有当相关的类加载器变得不可达时才会发生这种情况。如果这是你的问题,你需要阅读有关类加载器内存泄漏的资料。

0