Grails Heap space overflowing intermittently

末鹿安然 提交于 2020-01-24 21:08:34

问题


I have one of those joyous problems that is intermittent and hard to replicate.

After either minutes or days of operation my grails app on our Test server fails. I cannot replicate on Dev or my local.

The stacktrace pattern example here clipped off the middle as its 1000's lines (this will just keep going dumping like this until I restart Tomcat):

at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
Caused by: javax.servlet.ServletException: javax.servlet.ServletException: org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space
    at net.sf.ehcache.constructs.web.filter.Filter.logThrowable(Filter.java:143)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:91)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
......
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
Caused by: javax.servlet.ServletException: org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space
    at grails.plugin.cache.web.filter.AbstractFilter.logThrowable(AbstractFilter.java:116)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:70)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)

..................
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
Caused by: org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    ... 132 more
Caused by: java.lang.OutOfMemoryError: Java heap space

This looks like possibly an application error occurs, errorHandler is invoked which keeps calling itself...kaboom!

Environment:

  • Grails: 2.0.4
  • Tomcat: apache-tomcat-7.0.28
  • OS: Red Hat Enterprise Linux Server release 5.8 (Tikanga)

Java:

java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.8) (rhel-1.27.1.10.8.el5_8-x86_64)
OpenJDK 64-Bit Server VM (build 20.0-b11, mixed mode)

In Dev Java is (and this could be the main issue which I am trying to get SA to change in Test system)

java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) 64-Bit Server VM (build 20.5-b03, mixed mode)

The server currently only has anywhere from 0-5 users logged on but this ebbs and flows over a 24 hour period.

Heap space allocated is 5g and typically <20% is used.

There are 2 other odd things occuring in Test and not in Dev:

  • Logs, with almost no logging originally but due to issue have opened it up to DEBUG and RollingFile 100Meg files rolling off at the 50th. Logs are fine, logging app specific stuff until the Stack blows and then the only thing in them is the stack, same goes for the tomcat logging. This even when I shutdown the server well before the 50th log gets rolled off. So I have no idea if there is some app specic hoodoo going on that triggers this.

  • JavaMelody plugin: The labels on the graphs are unreadable kinda like my 3 year old wrote them. I believe all the OS fonts are loaded but could point to the Java version.

Schedulers: Yes there are 2 running, have run them without issue

DB Config: There are 8 dataSources to legacy DB's, each currently may be set a bit hungry, by example:

def connectionPropertiesMedium = [
        maxActive: 100,
        maxIdle: 30,
        minIdle: 5,
        initialSize: 30,
        testOnBorrow: true,
        testWhileIdle: false,
        testOnReturn: false,
        validationQuery: "SELECT 1",
        minEvictableIdleTimeMillis: 600000,
        timeBetweenEvictionRunsMillis: 600000,
        numTestsPerEvictionRun: 3,
        maxWait: 10000,
        defaultTransactionIsolation: java.sql.Connection.TRANSACTION_READ_UNCOMMITTED
]

HeapDump: Running with -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof Reading with VisualVM this reveals little (to me anyway) 70%+ is char[] full of the stacktraces above. Eclipse MAT wont load it.

JVM args:

CATALINA_OPTS="-server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof -XX:MaxPermSize=1024m -XX:MaxNewSize=256m -XX:NewSize=256m -Xms768m -Xmx1024m -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseTLAB -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSIncrementalMode -XX:-UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent

Stress test: There are a couple of intense queries the app can run, these are hit a few times by up to 200 simulated JMeter users without issue...actually the DB did have a bit of go slow ;) But the memory issue was not replicated on many runs.

So if anyone reads this far I have 2 leads (open to more):

  • Java version - aiming to get off OpenJDK and on to standard release
  • Something in my Grails setup that is causing infinite/recursive processing when an error occurs.

Until I find the proton packs that nuke these ghosts-in-the-machine are this app wont go-live.

Any ideas?

Cheers...

Update #1

Installed Java 1.7 and removed OpenJDK, this certainly fixed the JavaMelody display issue. Now its a waiting game to see if this fixed the primary issue. Interestingly the site seems noticeably faster.


回答1:


If the user resubmits the login form multiple times (to j_spring_security_check) it was causing a User.save() (eg to update last login time) being called in custom UserDetailsService, Hibernate session was closed on the subsequent calls for each user.

Moved the User.save() to AuthenticationEventListener.onApplicationEvent(AuthenticationSuccessEvent event) and it works fine.

Basic setup for this is from the docs at Spring security core plugin - events , mine is like:

To your config add: grails.plugin.springsecurity.useSecurityEventListener = true

In resources.groovy:

import security.AuthenticationEventListener
....
authenticationEventListener(AuthenticationEventListener)

AuthenticationEventListener.groovy:

class AuthenticationEventListener implements ApplicationListener<AuthenticationSuccessEvent> {

    void onApplicationEvent(AuthenticationSuccessEvent event) {
        if (event instanceof AuthenticationSuccessEvent) {
            UserDetails userDetails = (UserDetails) event.getAuthentication().getPrincipal()
            def httpSession = SecurityRequestHolder.request.session

            if (!httpSession.loggedIn) {
                httpSession.loggedIn = true
                synchronized (httpSession.loggedIn) {
                    httpSession.timeZone = userDetails.timeZone
                    User.withSession { session ->
                        if (session.isOpen()) {
                            User user = User.findByUsername(userDetails.username, [fetch: [roles: 'eager']])
                            user.lastLoggedIn = new Date()
                            user.save(flush: true)
                        }
                    }
                }
            }
        }
    }
}


来源:https://stackoverflow.com/questions/12064622/grails-heap-space-overflowing-intermittently

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!