Announcement Announcement Module
Collapse
No announcement yet.
OutOfMemoryError: PermGen space Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • OutOfMemoryError: PermGen space

    Hi,

    Whenever I deploy my war application several times (roughly 10) to my Sun Application Server 9, the following error occur regarding PermGen space:

    Code:
    2007-10-25 17:13:11,053 ERROR [org.springframework.web.servlet.DispatcherServlet] - Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/appframework-servlet.xml]: Invocation of init method failed; nested exception is java.lang.OutOfMemoryError: PermGen space
    Caused by: 
    java.lang.OutOfMemoryError: PermGen space
    	at java.lang.ClassLoader.defineClass1(Native Method)
    	at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
    	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
    	at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1997)
    	at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:948)
    	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1428)
    	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1292)
    	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
    	at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:203)
    	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1154)
    	at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory(LocalSessionFactoryBean.java:867)
    	at org.springframework.orm.hibernate3.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:779)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1201)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1171)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:425)
    	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
    	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
    	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:284)
    
    ...
    Any solution?
    Would that be my misconfiguration of the hibernate session factory? I've heard some people expending the memory but this would only solve the problem in short term only.

    Many thanks in advance!

  • #2
    What you have here is a classloader leak.

    The PermGen area holds stuff that the jvm thinks will be required permanently while the server is running. This includes, amongst other things, classes themselves.

    You're problem is that when you redeploy your app the jvm will load new classes for your new app but still holds onto some old ones as well. Stuff in PermGen is not garbage collected. Trying to trace what is being kept when it is no longer required is pretty painful but there are a couple of other things you can try:

    1. Increase the PermGen size - Add the jvm startup argument -XX:MaxPermSize=WHATEVER
    the default is 64m so maybe just double it
    You also should increase the Max jvm memory size along with the above e.g.
    -Xmx1024m

    2. Restart your server once in a while rather than just redeploy - This will clear up all the old PermGen rubbish as the jvm will be starting from scratch.

    Comment


    • #3
      3. Use BEA JRockit, which uses a different memory model and doesn't suffer from the earlier mentioned issue.

      Comment


      • #4
        You should also be aware of the "Big memory leak in the use of CGLIB" - see http://opensource.atlassian.com/proj...rowse/HHH-2481. This is fixed in HBN v3.2.3.

        The HBN folks keep talking about closing session factory on a servlet destroy. Is this done by default in the Spring servlet?

        Jeff

        Comment


        • #5
          Originally posted by jboring
          The HBN folks keep talking about closing session factory on a servlet destroy. Is this done by default in the Spring servlet?
          If I check my logging on a normal shutdown of my tomcat I see the following

          Code:
          2007-10-26 09:13:30,442 INFO  [org.springframework.scheduling.quartz.SchedulerFactoryBean] Shutting down Quartz Scheduler
          2007-10-26 09:13:31,927 INFO  [org.springframework.web.context.support.GenericWebApplicationContext] Closing org.springframework.web.context.support.GenericWebApplicationContext@2c70cf8: display name [org.springframework.web.context.support.GenericWebApplicationContext@2c70cf8]; startup date [Thu Oct 25 18:51:29 CEST 2007]; parent: [email protected]17726ce
          2007-10-26 09:13:31,927 INFO  [org.springframework.beans.factory.support.DefaultListableBeanFactory] Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2c70db2: defining beans [view-wub-archive-selection,users-report,view-vacationcard-search,view-wub-archive-spec,view-forgotpassword,error-translation-list,view-autorisatie-addcontactpersoon,view-autorisatie-user-organisaties-add,admin-roles-edit-role2,msgproperties-list,view-edit-personaldata,admin-consumers-edit-consumer,annual-statement-search,import-logging-search,select-assignment-cpn,filterorganisatie,view-vacationcard,wubflow-config-edit-scenario,admin-modules-view-modules,invoice-search,wubflow-config-edit-mail,view-password-expired,view-inschrijven-upload,wub-today-uzk,admin-user-rights2,generic_view,view-autorisatie-edituser,scp-edit,select-assignment-uzk,view-intake-autorisatie,wub-today-int,view-sidestimecard-report-messages-xml,view-inschrijven,view-password-reset,wub-by-assignment,admin-user-organisations,admin-roles-edit-role,admin-roles-view-roles,view-inschrijven-logoff,view-autorisatie-user-kostenplaatsen-add,view-first-time,view-error,report-users,captcha,view-sidestimecard-report-messages-list,msgproperties-edit,view-activation-sent,salary-search,generic-error-view,view-autorisatie-user-ogekps-list,view-autorisatie-modules,wubflow-config-staffing-customer-search,wub-today-cpn,edit-wub,login,webflow-error-view,view-inschrijven-info,error-translation-edit,admin-user-roles,admin-user-rights,select-assignment-int,scp-list,admin-consumers-view-consumers,admin-user-costplaces,view-sidestimecard-report-messages-edit]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@1800a95
          2007-10-26 09:13:31,927 INFO  [org.springframework.orm.hibernate3.LocalSessionFactoryBean] Closing Hibernate SessionFactory
          
          So conclusion is that Spring does shutdown everything nicely...

          Comment


          • #6
            Thanks folks

            To supplement my case a bit, I'm using HibernateUtil as helper class supplied by some documentations like:

            Code:
            public class HibernateUtil
            {
                private static final SessionFactory sessionFactory;
            
                static
                {
                    try
                    {
                        // Create the SessionFactory from hibernate.cfg.xml
                        sessionFactory = new Configuration().configure().buildSessionFactory();
                    }
                    catch (Throwable ex)
                    {
                        // Make sure you log the exception, as it might be swallowed
                        System.err.println("Initial SessionFactory creation failed." + ex);
                        throw new ExceptionInInitializerError(ex);
                    }
                }
            
                public static SessionFactory getSessionFactory()
                {
                    return sessionFactory;
                }
            }
            Whenever I need database access, I'll use the code like this:
            Code:
                    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
                    session.beginTransaction();
                    try
                    {
                        xyz = session.getNamedQuery("abc").list();
                        session.getTransaction().commit();
                    }
                    catch (HibernateException e)
                    {
                        session.getTransaction().rollback();
                        throw e;
                    }
                    finally
                    {
            	    session.close();
            	    HibernateUtil.getSessionFactory().close();        	
                    }
                    return xyz;
                }
            The "finally" block was just added. Do you think it is helpful in this memory issue?

            Comment


            • #7
              It might help your memory issue BUT it is a killer for your perfomance... This piece of code means that it closes/shutsdown the SessionFactory and each time a new call to the getSessionFactory method is made the sessionfactory is created/loaded again.

              However you are also mixin things up... You are using Spring to load/configure a SessionFactory but also have some utility class which again creates/instantiates a SessionFactory.

              Make sure you use only 1 SessionFactory... Don't use your helper class, kill it asap . Let SPring inject the session factory which it created...

              Comment


              • #8
                Thanks for the light

                Thanks for your prompt reply. Just tested that he closing of my session won't help in this memory issue.

                You're right. I may need to remove the HibernateUtil class. And also I need to remove my hibernate.cfg.xml too as it duplicates my session factory setting with those in my applicationContext.xml file.

                Will update this thread for any result.

                Comment


                • #9
                  and don't use JRockit. It has problems of its own, which may affect interoperabillity with Sun VMs (and others).

                  Comment


                  • #10
                    some related issues.

                    Hi Folks,

                    I can successfully remove most of my usage of Hibernate helper class except inside my own class extending the "LdapAuthenticationProvider". Originally I tried to get the user role from an external database by adding some code inside the "createUserDetails" function, like this:

                    Code:
                    public class LdapRoleAuthenticationProvider extends LdapAuthenticationProvider{
                    
                    	static Logger logger = Logger.getLogger(UserRoleAddController.class.getName());
                    	
                    	public LdapRoleAuthenticationProvider(LdapAuthenticator arg0, LdapAuthoritiesPopulator arg1) {
                    		super(arg0, arg1);
                    	}
                    
                    	protected UserDetails createUserDetails(LdapUserDetails ldapUser, String username, String password) {
                    		LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence(ldapUser);
                    		user.setUsername(username);
                    		user.setPassword(password);
                            ArrayList tempGrantedAuthorities = new ArrayList();
                            List userRoleList = getUserRoleList(username);
                            Iterator it = userRoleList.iterator();
                        	while (it.hasNext()){
                        		UserRole userRole = (UserRole)it.next();
                                GrantedAuthority temp = new GrantedAuthorityImpl(userRole.getRoleID());
                                tempGrantedAuthorities.add(temp);
                        		System.out.println("user role id: " + userRole.getRoleID());
                        	}
                            GrantedAuthority[] extraAuthorities = new GrantedAuthority[tempGrantedAuthorities.size()]; 
                            tempGrantedAuthorities.toArray(extraAuthorities);
                    		for (int i = 0; i < extraAuthorities.length; i++) {
                                user.addAuthority(extraAuthorities[i]);
                            }
                            return user.createUserDetails();
                        }
                    
                    }
                    Since I cannot extend the HibernateDaoSupport together with LdapAuthenticationProvider, is there any elegant way to use the getHibernateTemplate().findByNamedQueryAndNamedPar am() inside my own LdapRoleAuthenticationProvider?

                    Comment


                    • #11
                      You can create a HibernateTemplate yourself. Simply inject the SessionFactory (as you do with the dao objects and inside the setter create a hibernatetemplate).

                      Code:
                      private HibernateTemplate hibernateTemplate;
                      
                      public void setSessionFactory(SessionFactory sessionFactory) {
                        hibernateTemplate = new HibernateTemplate(sessionFactory);
                      }
                      That should work or instead of the SessionFactory create a HibernateTemplate in your ApplicationContext.xml and inject that.

                      Comment


                      • #12
                        Thanks.

                        your suggestion make sense.
                        however, I'm still finding a place for injecting my sessionFactory. Could I just inject it inside my own LdapAuthenticationProvider. A portion of my config is:

                        Code:
                        <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
                        	<property name="providers">
                        		<list>
                        			<ref local="ldapRoleAuthenticationProvider" />
                        		</list>
                        	</property>
                        </bean>
                        <bean id="ldapRoleAuthenticationProvider" class="com.fimat.security.util.LdapRoleAuthenticationProvider">
                        	<constructor-arg>
                        		<bean class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
                        			...
                        		</bean>
                        	</constructor-arg>
                        	<constructor-arg>
                        		<bean class="org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">
                        			<constructor-arg>
                        				<ref local="initialDirContextFactory"/>
                        			</constructor-arg>
                        			<constructor-arg>
                        				...
                        			</constructor-arg>
                        			<property name="groupRoleAttribute">
                        				...
                        			</property>
                        		</bean>
                        	</constructor-arg>
                        </bean>
                        I try to embed the HibernateTemplate but find no way to inject the sessionFactory:

                        Code:
                        public class LdapRoleAuthenticationProvider extends LdapAuthenticationProvider{
                        
                        	public LdapRoleAuthenticationProvider(LdapAuthenticator arg0, LdapAuthoritiesPopulator arg1) {
                        		super(arg0, arg1);
                        	}
                        
                        	private HibernateTemplate hibernateTemplate;
                        	public void setSessionFactory(SessionFactory sessionFactory)
                        	{
                        		hibernateTemplate = new HibernateTemplate(sessionFactory);
                        	}
                        	public List getUserRoleList(String userID)
                        	{
                        		return hibernateTemplate.findByNamedQueryAndNamedParam("getRolesAuthenticated", "user_id", userID);
                        	}
                        }
                        Sorry for posting long code and appreciated for any suggestions.

                        Comment

                        Working...
                        X