【问题标题】:OutOfMemoryError during long batch on Grails/Tomcat在 Grails/Tomcat 上长批处理期间出现 OutOfMemoryError
【发布时间】:2010-11-15 01:10:14
【问题描述】:

我正在我的 Grails 应用程序上运行一个长批次。该服务联系 Web 服务并下载本地存储在 grails 应用程序(在数据库中)中的 xml。 下载的对象非常大且复杂,应用程序会处理它们并创建本地域对象。 我正在使用 Grails 1.2.2,因为我无法将我的应用程序升级到最新版本(我花了几个小时在它上面,然后我扔了海绵)。

这基本上是一个很长的 for 循环,迭代之间几乎没有共享信息。

有点像:

while( stillObjectsToDo ){
   def bigObj = myservice.fetchXML
   def localInstance = myservice.processObj( bigObj )
   localInstance.saveEverythingToDB
   clearGORM
}

我在 Tomcat 上运行该应用程序,该应用程序已针对增加堆大小进行了调整。 当我处理一个对象时,我从来没有遇到过问题。但是当我运行整个批次(大约 1500 个大对象)时,我总是得到:

codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionException: Executing action [runSampleBatch] of controller [semanticopenstreetmap.EngineController]  caused exception: java.lang.OutOfMemoryError: Java heap space
 at java.lang.Thread.run(Thread.java:619)
Caused by: org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.OutOfMemoryError: Java heap space
 ... 1 more
Caused by: java.lang.OutOfMemoryError: Java heap space
 at java.util.Arrays.copyOf(Arrays.java:2882)

这似乎是某种内存泄漏,但我找不到它。这真的很奇怪,因为对象存储在数据库中并且不再在过程中使用,所以它们应该被刷新。

我尝试了以下解决方案来避免这个问题,但没有成功:

  • 在每次迭代中刷新每个对象后清除 休眠会话
  • 每 5-6 分钟调用一次垃圾收集器
  • 在循环结束时手动取消之前的对象(可能没用)。

这些都没有奏效。内存使用量不断增长。 我使用了虚拟虚拟机,得到了这张图: http://img12.imageshack.us/img12/5660/memoryleak.png 和课程: http://img263.imageshack.us/img263/331/memoryleakclasses.png

如何定位并解决此内存泄漏?

编辑:在单独的线程中运行每个对象是否有意义?内存泄漏发生在 http-0-x 进程中,如何检查这个对象?

有什么提示吗?

谢谢!

穆龙

【问题讨论】:

  • 你用的是什么抓取收集器?
  • 我使用的是默认的:Runtime.getRuntime().totalMemory() 和 Runtime.getRuntime().freeMemory()

标签: hibernate tomcat grails memory-management memory-leaks


【解决方案1】:

我会使用 Visual VM 附加到进程并查看内存情况。

我想知道动态生成的代理是否正在填满您的 perm gen 空间。 Visual VM 将为您提供所需的证据,看看这是否属实。

【讨论】:

  • 从追踪上看,这似乎不是 permgen 问题;它似乎是一个“正常的”OOM。
【解决方案2】:

这是一个潜在的探索领域:Troubleshooting Grails/Groovy memory leaks?

【讨论】:

    【解决方案3】:

    您需要将外部分析器附加到您的应用。这是一个很好的。

    https://visualvm.dev.java.net/

    基本的想法是您向您的 tomcat 启动脚本添加一些选项,启动 tomcat 和您的分析器,然后使用您的应用程序。您将看到实时更新,并能够看到您的内存被消耗、释放等等。

    您应该看到的是一个上升、然后下降、然后上升、然后下降等等的图表。关键是,虽然内存使用量会周期性上升,但随着时间的推移,基线没有上升趋势。因此,当图表下降时,随着时间的推移,它会回落到某个基线。如果在图表下降后,您看到上升趋势,您需要确定应用程序的哪个区域导致它。 VisualVM 具有分析堆的方法,因此您可以查看每种类型存在多少对象。您应该使用该工具来确定哪些对象没有被收集。

    【讨论】:

    • 我正在使用 Visual VM,我可以看到堆增长非常缓慢,直到它产生内存不足错误。我每 5-6 分钟打电话给 GC,但似乎并没有解决问题。实际上,如果我从 Visual VM(从按钮)调用 GC,效果会好得多。有什么想法吗?
    【解决方案4】:

    GORM 中存在一个已知的内存泄漏,无法通过清除会话来修复。 Burt Beckwith 写了它here。基本上,解决方法是调用DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP.get().clear()

    【讨论】:

    • 谢谢!我已经将它包含在 clearGORM 函数中,但它似乎不起作用
    • 从您的分析器屏幕截图中,似乎有大量 char[] 对象正在污染堆。您的分析器是否允许您查看这些实例的分配位置?也许正在获取 XML 的服务正在某处缓存响应?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多