问题
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