grails - 如何避免导致 OutOfMemoryException 的巨大查询结果

标签 grails groovy service grails-orm

这是我的情况:

从我的 Grails Controller 中,我调用了一个服务,它以只读方式查询数据库,将结果转换为 JSON,然后返回结果。

规范是:JDK 1.6、Tomcat 5.5、Grails 1.3.4、DB via JNDI

Tomcats MaxPermSize 设置为 256m,Xmx 设置为 128m。
编辑:增加内存应该是最后的手段

服务方式:

  String queryDB(String queryString) {
    StringWriter writer = new StringWriter()
    JSonBuilder json = new JSonBuilder(writer)
    def queryResult = SomeDomain.findAllBySomePropIlike("%${queryString}%")

    json.whatever {
      results {
        queryResult.eachWithIndex { qr, i ->
          // insert domain w/ properties
        }
      }
    }
    queryResult = null
    return writer.toString()
  }

现在,当 queryString == 'a' 结果集很大时,我得到了这样的结果:

[ERROR] 03/Nov/2010@09:46:39,604 [localhost].[/grails-app-0.1].[grails] - Servlet.service() for servlet grails threw exception
java.lang.OutOfMemoryError: GC overhead limit exceeded
    at org.codehaus.groovy.util.ComplexKeyHashMap.init(ComplexKeyHashMap.java:81)
    at org.codehaus.groovy.util.ComplexKeyHashMap.<init>(ComplexKeyHashMap.java:46)
    at org.codehaus.groovy.util.SingleKeyHashMap.<init>(SingleKeyHashMap.java:29)
    at groovy.lang.MetaClassImpl$Index.<init>(MetaClassImpl.java:3381)
    at groovy.lang.MetaClassImpl$MethodIndex.<init>(MetaClassImpl.java:3364)
    at groovy.lang.MetaClassImpl.<init>(MetaClassImpl.java:140)
    at groovy.lang.MetaClassImpl.<init>(MetaClassImpl.java:190)
    at groovy.lang.MetaClassImpl.<init>(MetaClassImpl.java:196)
    at groovy.lang.ExpandoMetaClass.<init>(ExpandoMetaClass.java:298)
    at groovy.lang.ExpandoMetaClass.<init>(ExpandoMetaClass.java:333)
    at groovy.lang.ExpandoMetaClassCreationHandle.createNormalMetaClass(ExpandoMetaClassCreationHandle.java:46)
    at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.createWithCustomLookup(MetaClassRegistry.java:139)
    at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.create(MetaClassRegistry.java:122)
    at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:165)
    at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:182)
    at org.codehaus.groovy.runtime.callsite.ClassMetaClassGetPropertySite.<init>(ClassMetaClassGetPropertySite.java:35)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.createClassMetaClassGetPropertySite(AbstractCallSite.java:308)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.createGetPropertySite(AbstractCallSite.java:258)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.acceptGetProperty(AbstractCallSite.java:245)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:237)
    at org.codehaus.groovy.grails.plugins.web.filters.FilterToHandlerAdapter.accept(FilterToHandlerAdapter.groovy:196)
    at org.codehaus.groovy.grails.plugins.web.filters.FilterToHandlerAdapter$accept.callCurrent(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:143)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:159)
    at org.codehaus.groovy.grails.plugins.web.filters.FilterToHandlerAdapter.preHandle(FilterToHandlerAdapter.groovy:107)
    at org.springframework.web.servlet.HandlerInterceptor$preHandle.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
    at org.codehaus.groovy.grails.plugins.web.filters.CompositeInterceptor.preHandle(CompositeInterceptor.groovy:42)
    at org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet.doDispatch(GrailsDispatcherServlet.java:282)

我在网上找到的一种方法是关于 Hibernate 和域验证中的一些泄漏,解释为 here并详细介绍here .我正要测试它,但我不知道这是否真的是我的问题的解决方案以及(如果是的话)什么时候最好清理 GORM。

或者我的代码中是否还有其他内存泄漏? 有什么想法吗?

编辑:就我现在而言,异常发生在调用 finder 方法的地方。这意味着 GORM 无法处理数据库返回的数据量,对吧?很抱歉像新手一样问,但我从未遇到过这样的问题,即使结果集非常大。

最佳答案

Sun (此链接已失效)had documented这个OutOfMemoryError如下:

The parallel / concurrent collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.

换句话说,该错误是一项功能,是增加可用内存的提示(正如您所提到的,这不是您的首选选项)。部分开发者consider此功能并非在所有用例中都有用,因此请检查是否将其关闭。

关于grails - 如何避免导致 OutOfMemoryException 的巨大查询结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4085958/

相关文章:

grails - 更改Quartz作业创建的默认位置

groovy - Gradle 操作顺序

c# - 通过HTTP访问WCF服务

html - 在 gsp 模板中渲染内容

grails - 有什么方法可以覆盖默认的 Camel FatalFallbackErrorHandler 吗?

Groovy swingbuilder 文档和示例

linux - Docker 容器作为 Linux 服务?

java - android.os.ServiceManager 无法解析

events - 找不到Grails Spring Events插件

grails - 使用 Grails 进行服务器推送?