What causes the ‘java.lang.OutOfMemoryError: PermGen space’ error in a Hibernate/JPA + IceFaces/JSF application running on Tomcat 6 and JDK 1.6, and how can it be prevented or fixed, especially when it occurs after redeploying the application multiple times?
The java.lang.OutOfMemoryError: PermGen space error in Hibernate/JPA + IceFaces/JSF applications on Tomcat 6 with JDK 1.6 primarily occurs due to ClassLoader memory leaks during redeployment, where class metadata accumulates in the PermGen space without proper garbage collection. This happens because static references, cached objects, and thread pools maintain references to ClassLoaders preventing cleanup, especially when using JSF components and Hibernate ORM. The error manifests after multiple redeployments as the PermGen space fills with class definitions that cannot be garbage collected.
Contents
- What is PermGen Space and Why It Matters
- Root Causes of the Error in Hibernate/JPA + JSF Applications
- Practical Solutions and Prevention Strategies
- Diagnostic Tools and Analysis Methods
- Long-term Migration Recommendations
What is PermGen Space and Why It Matters
The Permanent Generation (PermGen) space in JDK 1.6 is a special heap area where the JVM stores class metadata, including class definitions, method code, and constant pool information. Unlike the main heap, the PermGen space has its own garbage collection mechanism that’s much less efficient. In Tomcat 6, each web application gets its own WebappClassLoader, and when redeploying applications, these ClassLoaders should theoretically be garbage collected when no longer needed.
However, as explained by Mattias Jiderhamn, the PermGen space creates a perfect storm for memory leaks because “the permanent generation is not sweeped by the garbage collector” as noted in the JBoss discussion. Each redeployment adds more class definitions to PermGen, and when ClassLoader leaks prevent cleanup, the space eventually fills up completely.
The problem is particularly acute with applications using Hibernate/JPA and IceFaces/JSF because these frameworks create complex object hierarchies and caches that can maintain references preventing proper garbage collection of ClassLoaders.
Root Causes of the Error in Hibernate/JPA + JSF Applications
ClassLoader Memory Leaks
The primary cause of PermGen errors is ClassLoader memory leaks. When a web application is undeployed, the container should drop all references to that ClassLoader, allowing normal garbage collection to clean up the associated classes. However, as Victor Jan explains, “When an application is undeployed, the container in theory drops all references to that class loader, and expects normal garbage collection to take care of the rest” - but this theory doesn’t always work in practice.
Specific problematic patterns include:
-
Static references: As noted in the Stack Overflow discussion, “As the reference is originally static, no amount of garbage collecting will clean this reference up - the ClassLoader, and all the classes it’s loaded, are here to stay.”
-
Thread pools: Thread pools that maintain references to application classes prevent ClassLoader cleanup. As Mkyong states, “Most often the java.lang.OutOfMemoryError: Permgen space is triggered during redeploys when buggy code blocks classloaders from being garbage collected.”
Framework-Specific Issues
JSF and IceFaces Issues:
The JSF API, particularly javax.faces.component.UIComponentBase, contains a cache that can cause ClassLoader leaks when the API is at the application server level. This is a known issue that affects JSF-based applications heavily.
Hibernate/JPA Issues:
Hibernate can cause memory leaks through several mechanisms:
- CGLIB proxy generation creates classes that may maintain references
- Javassist (used by older Hibernate versions) has had known PermGen issues
- Connection pooling and cleanup thread problems
As noted in the Spring Data JPA memory leak discussion, the MySQL JDBC driver can create cleanup threads that maintain references, preventing proper ClassLoader garbage collection.
Tomcat 6 Specific Limitations
Tomcat 6 has specific limitations that exacerbate these issues:
- The default PermGen size is relatively small (64MB)
- ClassLoader handling during redeployment has known bugs
- Integration with various application frameworks creates edge cases
As mentioned in the research, “They Say that the latest rev of Tomcat (6.0.28 or 6.0.29) handles the task of redeploying servlets much better” but even these versions have limitations with complex applications.
Practical Solutions and Prevention Strategies
Immediate Fixes
Increase PermGen Size:
The quickest fix is to increase the PermGen space allocation. Set these JVM parameters in your CATALINA_OPTS or JAVA_OPTS:
export CATALINA_OPTS="-XX:MaxPermSize=512m -XX:PermSize=256m"
As noted in the TecAdmin guide, “Increasing the permgen size will delay the point at which it runs out of memory, but really, you need to ensure Tomcat gets bounced when you redeploy a webapp.”
Restart Tomcat After Redeployment:
While not ideal for development environments, restarting Tomcat after each redeployment ensures complete cleanup. This is often the most reliable temporary solution.
Code and Configuration Fixes
Fix ClassLoader Leaks:
-
Update library versions: Use the latest versions of Hibernate, JSF, and related libraries. As Mattias Jiderhamn notes, “I’ve seen reports on the net about PermGen errors when using older versions of Javassist for example with Hibernate. There are lots of issues in Javassist JIRA; start here and see ‘Similar Issues’. Since the issues have different fixed versions, you better use the latest version.”
-
Configure JDBC drivers properly: As recommended in the Spring Data JPA discussion, “This forces the MySQL JDBC driver, and its cleanup thread, to be loaded outside the classloader for the web application.”
-
Use ClassLoader Leak Protector: Try the ClassLoader Leak Prevention library specifically designed to address these issues.
Hibernate Configuration:
Configure Hibernate to be more memory-friendly:
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.use_query_cache">false</property>
JSF Configuration:
- Clear JSF component caches properly
- Ensure proper cleanup of FacesContext instances
- Consider using JSF 2.x features that handle memory better
Advanced Configuration Options
Garbage Collection Tuning:
export CATALINA_OPTS="-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSIncrementalMode"
The -XX:+CMSClassUnloadingEnabled flag is particularly important as it allows the garbage collector to unload classes from the PermGen space.
Heap Dump Analysis:
Configure your JVM to generate heap dumps on OutOfMemoryError:
export CATALINA_OPTS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps"
Diagnostic Tools and Analysis Methods
Eclipse Memory Analyzer Tool (MAT)
Eclipse MAT is the most effective tool for analyzing PermGen leaks. As noted in the Stack Overflow discussion, “When deployed on Tomcat with VM option -XX:+HeapDumpOnOutOfMemoryError, the generated heap dump can be analysed with Eclipse Memory Analyzer Tool (MAT). MAT identifies the class java.util.logging.Level$KnownLevel as the culprit that prevents garbage collection.”
MAT can help you:
- Identify objects preventing ClassLoader garbage collection
- Find static references that shouldn’t exist
- Analyze the chain of references causing leaks
VisualVM
Use VisualVM that comes with the JDK to:
- Monitor memory usage over time
- Take snapshots before and after redeployment
- Analyze thread dumps to identify problematic threads
Manual Analysis Techniques
Monitoring PermGen Usage:
jstat -gcutil <pid> 1000
This will show you PermGen usage percentage over time, helping you identify when the space is filling up.
Class Loading Analysis:
jmap -permstat <pid>
This command provides statistics about permanent generation space usage by class loader.
Long-term Migration Recommendations
Upgrade to JDK 7+ and Tomcat 7+
The most sustainable solution is to migrate to newer technologies where the PermGen space has been replaced by the Metaspace in JDK 8+, which has much better garbage collection characteristics.
JDK 8 Migration Benefits:
- Metaspace automatically grows and shrinks
- No fixed size limits
- Better garbage collection of class metadata
- Native memory management which is more efficient
Tomcat 7+ Benefits:
- Improved ClassLoader handling
- Better memory leak detection
- Enhanced redeployment mechanisms
Architecture Improvements
Container Isolation:
Consider running applications in separate containers to prevent cross-contamination of ClassLoaders.
Microservices Approach:
Break down large applications into smaller services to reduce the memory footprint of each deployment.
Development Process Improvements:
- Implement proper testing before deployment
- Use continuous integration to catch memory leaks early
- Monitor application memory usage in production
Conclusion
The java.lang.OutOfMemoryError: PermGen space error in Hibernate/JPA + IceFaces/JSF applications on Tomcat 6 is primarily caused by ClassLoader memory leaks during redeployment, where class metadata accumulates without proper garbage collection. The key solutions include increasing PermGen size temporarily, fixing ClassLoader leaks through proper configuration and library updates, and using diagnostic tools like Eclipse MAT to identify the root causes. For long-term stability, migrating to JDK 8+ with Metaspace and Tomcat 7+ provides the most robust solution by eliminating the PermGen space entirely and implementing better memory management practices.
Sources
- Dealing with “java.lang.OutOfMemoryError: PermGen space” error - Stack Overflow
- Tomcat – java.lang.OutOfMemoryError: PermGen space Cause and Solution - Javarevisited
- Tomcat - java.lang.OutOfMemoryError: PermGen space - Mkyong.com
- Tomcat – java.lang.OutOfMemoryError: PermGen space – TecAdmin
- Classloader leaks V – Common mistakes and Known offenders - Mattias Jiderhamn
- Memory leaks where the classloader cannot be garbage collected - Victor Jan
- How to avoid Classloader Leak with JPA, Hibernate and Spring on Tomcat - Stack Overflow
- Tomcat 7+ memory leak on stop/redeploy. Spring Data, JPA, Hibernate, MySQL - Stack Overflow