java.lang.OutOfMemoryError: PermGen space on web app usage
Asked Answered
S

5

11

I am struggling with an outOfMemory PermGen issue that has been showing up recently. One of the log snippets that was saved when error appeared:

java.lang.OutOfMemoryError: PermGen space
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
        at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.findClass(ModuleImpl.java:1872)
        at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:720)
        at org.apache.felix.framework.ModuleImpl.access$300(ModuleImpl.java:73)
        at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1733)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:248)

I've increased max perm size -XX:MaxPermGen=128m but this is just a temporary solution because I am preety sure we are facing some memory leak here. The web part of our applications is deployed on jetty (jsf + icefaces). Clicking on random components increases the memory used - I am monitoring it with jstat -gcold and nearly every hit means 3-4kb more. I've added -XX:+TraceClassLoading to the jvm params and see many sun.reflect.GeneratedConstructorAccessor and sun.reflect.GeneratedMethodAccessor being logged when there is any action on the web user interface. I also made a heap dump when 99% of permgen was used. I used YourKit profiler to analyze the heap. In the class loader tab there are loaads of sun.reflect.DelegatingClassLoader rows with 1 class for each. What might be causing the memory to constantly grow? Any help will be really appreciated.

thanks in advance, Lukasz

Salesperson answered 21/2, 2011 at 12:40 Comment(2)
What was the value of MaxPermGen before you increased it?Teller
Jvm used its default value that was 84mb.Salesperson
P
5

On the Sun JVM, reflective access to properties and methods is initially performed by calling through JNI into the JVM implementation. If the JVM notices that a method or field is being accessed by reflection a lot, it will generate bytecode to do the same thing -- a mechanism that it calls "inflation". This has an initial speed hit, but after that runs about 20 times faster. A big win if you do a lot of reflection.

That bytecode lives in classes created by DelegatingClassLoader instances and take up permgen space. If it is a problem, you can turn inflation off by setting the system property sun.reflect.inflationThreshold to 0 (zero).

Prospero answered 9/1, 2012 at 13:54 Comment(0)
K
4

First of all, this is not specifically related to JSF. You're simply giving your appserver too little memory as compared to the needs of your webapp. You would have the same problem with every other framework which uses under the covers a good shot of reflection (think of all those EL resolvings). This can be JSF, Wicket, Spring-MVC and even plain JSP/Servlet. The chance is only bigger on component based web frameworks which rely heavily on EL resolvers, such as JSF (and others).

Further it's known that Tomcat (-based) servers may cause this as well when you (hot)redeploy a bit too often. Get yourself through the following links to learn about it and how to deal with it:

Knut answered 21/2, 2011 at 15:31 Comment(4)
I just have a strange feeling that no matter how much memory will I assign to the permanent generation it will still be able to clog it up - at least the way it behaves lets me think so. After the application is deployed permgen is used in 60%. A ride through all the components (so that all basically all the classes are loaded) pops up the permgen usage to around 65%. Then, with a little help of squish automated tests I was easy able to increse the usage to nearly 80%. I guess all the reflection based loaded classes is a expection behaviot, just don't know why are't they being unloaded.Salesperson
These things always make me wonder: Does .NET suffer from the same pain? They use a generational GC algorithm; their Strings are immutable; they have reflection. Do they feel our pain? What do they do about it? I've worked on an app that was deployed on WebLogic that never needed a server reboot: no leaks, no connections lost. Was the app server the only difference?Erasmoerasmus
@Lukasz: JSF serializes a limited amount of the views in the session (by default 15, configureable by a context param). Once you've used ALL possible expressions it will be stable. You just need to ensure that the server has enough memory to work with. Stresstest for example with JMeter with 100 concurrent users to learn about the borders. @Duffymo: I have no idea about .NET or Weblogic, but I know that IIS has basically no softwarebased memory limits, it's basically free to use as many memory as Windows available has. Weblogic has likely much higher default memory limit (like Glassfish).Knut
@Lukasz: it boils down that you've relatively complex JSF views and that Tomcat simply ships with a relatively low memory limit by default. All just needs to be aligned/adjusted based on stresstests.Knut
H
3

I would suggest using Eclipse MAT and to follow this tutorial dedicated to permgen problems.

Although as duffymo noticed you've done a great job analyzing the problem, the very origin of the problems seems still unknown. Maybe it's just one of the components, some parser (as jwenting suggests) or similar. The problem doesn't necessarily mean you need to throw away JSF from the stack.

Hexapartite answered 21/2, 2011 at 13:59 Comment(1)
I tried MAT as well, but that's basically the same what YourKit shows - numerous sun.reflect.DelegatingClassLoader entriesSalesperson
E
1

First of all, kudos to you for doing such a thorough job of investigating this and an even better job of writing your question. The world (and this site) would be a better place if everyone was as talented and as good a writer as you are.

I think you've already found the answer: I think JSF and its use of reflection is your problem.

This is one reason why I avoid JSF like the plague.

In my opinion, JSF is a failed extension of Struts. I'd consider an HTML/CSS/JavaScript/AJAX UI to be as capable as JSF, if not more so, and far less taxing on my JVM. The UI calls services and stays nice and separate from the server side.

Erasmoerasmus answered 21/2, 2011 at 12:49 Comment(3)
Thank you, however we are too far now to even consider changing the web framework.Salesperson
false impression. perm gen issues existed before the advent of JSF. the struts/tiles 1.x family has a permgen leak. other frameworks do too. there are various articles on different causes. one of the primary points that they all point to is orphaned object/classes that cannot be GBed because of linkages to other classloader artifacts. thus you get a chicken and egg issue that prevents the class/object from being GCed and memory leaks. google the various articles, and see if your code or any third party code you're using is "culpable". TIAParamilitary
Not a false impression. Of course perm gen issues can happen without JSF. I just happen to have observed one particularly awful JSF implementation that made it possible to time page refreshes with a sundial. I recommend avoiding it like the plague. I love it when people who are new to SO decide to spend their time making inane comments like this on questions that are 1.5 years old.Erasmoerasmus
N
0

Permgen problems are usually caused by some process doing a LOT of String.intern() operations. Some XML/HTML generators and parsers are guilty of this. Look there first, you may hit on the culprit quickly.

Navy answered 21/2, 2011 at 13:35 Comment(1)
Out app does not use them, maybe some 3rd parties do - gonna take a peek, thanks.Salesperson

© 2022 - 2024 — McMap. All rights reserved.