2

试图检测 webapp 中的内存泄漏。

  • 在崩溃时获取应用程序的堆转储。
  • 使用 Eclipse MAT 解析转储。

来自解析的整理信息导致这两个结论 -

  1. 占用更多内存的对象没有 GC 根。基本上每当 GC 发生时,它们都会被清理掉。
  2. GC 根下的对象占用的内存要少得多。所以这些可能不是内存泄漏的根本原因(?)。

那么这是否意味着没有泄漏发生?并且由于内存不足错误而发生崩溃?

编辑:添加环境信息

  • 我在 tomcat 6 上运行 java webapp。
  • webapp基于openreports(报告工具)

添加最大对象的传入引用列表——

http://imgur.com/lYrju

这里哈希映射的每个实例都有一个来自 com.opensymphony.xwork2 的引用,它不是 GC 收集的。这可能是问题的根源。因为tomcat日志说-

SEVERE: The web application [/openreports] created a ThreadLocal with key of type [com.opensymphony.xwork2.ActionContext.ActionContextThreadLocal] (value [com.opensymphony.xwork2.ActionContext$ActionContextThreadLocal@7c45901a]) and a value of type [com.opensymphony.xwork2.ActionContext] (value [com.opensymphony.xwork2.ActionContext@3af7dab3]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.
SEVERE: The web application [/openreports] created a ThreadLocal with key of type [com.opensymphony.xwork2.inject.ContainerImpl$10] (value [com.opensymphony.xwork2.inject.ContainerImpl$10@258c27bd]) and a value of type [com.opensymphony.xwork2.inject.InternalContext[]] (value [[Lcom.opensymphony.xwork2.inject.InternalContext;@1484fc8d]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.

编辑:添加 OOM 错误的堆栈跟踪

java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOfRange(Arrays.java:3209)
        at java.lang.String.<init>(String.java:215)
        at java.lang.StringBuffer.toString(StringBuffer.java:585)
        at java.io.StringWriter.toString(StringWriter.java:193)
        at org.displaytag.tags.TableTag.writeExport(TableTag.java:1503)
        at org.displaytag.tags.TableTag.doExport(TableTag.java:1454)
        at org.displaytag.tags.TableTag.doEndTag(TableTag.java:1309)
        at org.efs.openreports.engine.QueryReportEngine.generateReport(QueryReportEngine.java:198)
        at org.efs.openreports.util.ScheduledReportJob.execute(ScheduledReportJob.java:173)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:529)
10:01:04,193 ERROR ErrorLogger - Job (90.70|1338960412084 threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.OutOfMemoryError: Java heap space]
        at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:529)
Caused by: java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOfRange(Arrays.java:3209)
        at java.lang.String.<init>(String.java:215)
        at java.lang.StringBuffer.toString(StringBuffer.java:585)
        at java.io.StringWriter.toString(StringWriter.java:193)
        at org.displaytag.tags.TableTag.writeExport(TableTag.java:1503)
        at org.displaytag.tags.TableTag.doExport(TableTag.java:1454)
        at org.displaytag.tags.TableTag.doEndTag(TableTag.java:1309)
        at org.efs.openreports.engine.QueryReportEngine.generateReport(QueryReportEngine.java:198)
        at org.efs.openreports.util.ScheduledReportJob.execute(ScheduledReportJob.java:173)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
4

1 回答 1

0

您正在运行 ASP.NET WebForms(不是 MVC)应用程序吗?我们在我们的应用程序中遇到了类似的问题,这些是我们遇到的问题。首先,我应该声明我们的网络农场由许多应用程序池组成,当然每个客户端一个。每个应用程序池都有一个特定的内存限制,以确保客户端不会使内存失控并影响其他工作进程。

1) 即使对象没有根,如果它们超过 85K,它们将被放置到大对象堆上,.NET 的 GC 不会压缩。这意味着如果您有一个 100K 的对象,它将位于 LOH 上。清理完对象后,您将获得 100K,而 GC 可能会决定在该洞中放入其他东西。由于它没有被压实,你永远不能保证空间被完全填满。这会在未完全填满的空间中留下空洞,并导致内存碎片。解决此问题的唯一方法是检查您的转储文件并查看哪些对象占用了最大空间并确定可以削减的类/集合。您可能会看到很多对象数组和字符串,因为它们在缓存管理器等中通常相当大。

2)您是否正在处理实例?等待终结器线程来清理实例不应该是默认情况,因为这会导致糟糕的 GC 性能。确保您在其继承的某处处置所有实现 IDisposable 接口的类。提前调用 Dispose 意味着资源以确定性的方式释放,而依赖于终结器意味着清理可以在很久很久以后发生(如果有的话)。

3) 如果您遇到 OutOfMemoryExceptions,可能是由于两个原因:您用尽了托管内存(在设置了限制的工作进程的情况下很少见,因为它将被回收)或者您用完了虚拟内存,这更糟糕的是,如果您在 32 位 IIS 应用程序中运行,您将被限制为 2GB 的虚拟内存。我们还在生产环境中看到了这个问题,其中 GC 分配了 64MB 堆块(在工作站模式下为 32GB),一旦接近 2GB 限制并且无法分配更多空间,它就会抛出异常(请参阅:我们应该使用“工作站”垃圾收集还是“服务器”垃圾收集?)。如果是这种情况,

如果您可以发布您的转储文件或至少它的相关部分,则更容易看出问题所在。但从你的简短描述来看,这些是我要看的项目。

于 2012-12-10T09:37:05.830 回答