Chris,

>> I work on application which allows user to deploy/undeploy large 
>> number of the JSP pages to AppServer (JBoss 4.03sp1 + Tomcat 5.5). 
>> Standard Tomcat class loader caches classes for all deployed JSP 
>> internally and never clean its cache. This brings JVM to PermGen 
>> overflow error after several days of system work.
>
>Ouch. Are you saying that the sheer number of classes in your system 
>is overflowing your memory? 

Yes.

>That doesn't seem likely.
>
>After tomcat compiles your JSP, it loads the resulting class and
>executes it like a servlet.

I know.

>If you have an option enabled, it will detect updated JSPs, re-compile
>them, and reload them. It is certainly possible that when this happens,
>Tomcat discards the entire ClassLoader and starts fresh. In that case,
>if you have 10,000 JSPs, then each time you reload, you'll get 10,000
>more classes loaded into memory. If this happens enough times, you'll
>run out of memory since Java does not clean up old, unused classes in
>memory.

I have made some research. Looks like JVM unloads classes from PermGen, 
when classloader instance, used for loading these classes, is destroyed 
by GC. See program attached to the letter. It simply loads classes from
specified dir. This program is intended to be monitored by jconsole.

>Is this the behavior you are describing? 

Yes.

>If so, then you can't fix the
>problem by writing your own JSP compiler and/or ClassLoader. 

I guess loading each JSP class by separate classloader instance 
will fix the problem. Classloader will be created when HTTP request 
recived and no one reference on this classloader instance will be 
stored during request processing, so it can be destroyed by GC.

>Your best bet is not to modify your JSPs and have them re-loaded.
>
>Is this in a development setting or production? I would say that 
>having JSP reloading turned on in production is a mistake.

I am working on system for business processes processing. Each 
business process can be deployed and launched by user many times. 
Business process can contain JSP(JSF) pages, also it can contain 
Java-scriplets (POJO classes) with business logic. Each scriplet is 
loaded with separate classloader and therefore successfully unloaded 
from PermGen when classloader destroyed. All JSP classes are loaded 
by the one Tomcat classloader and can't be unloaded from memory. 
This is the problem.

Any ideas?

--
Nikita
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;

public class JTest {
	
	/**
	 * Load class from specified dir
	 */
	private static class SimpleClassLoader extends ClassLoader {
		private String classPath = null;
		
		public SimpleClassLoader(String classPath) {
			this.classPath = classPath;
		}
	    
		private byte[] loadClassData(File f) throws IOException {
	        FileChannel in = new FileInputStream(f).getChannel();
	        ByteBuffer buf = ByteBuffer.allocate((int) in.size());
	        in.read(buf);
	        in.close();
	        return buf.array();
	    }

		public Class findClass(String name) throws ClassNotFoundException {
			try {
				System.out.println("Loading " + name);
				String classFileName = name.replace('.', '/') + ".class";
				byte[] buf = loadClassData(new File(classPath, classFileName));
				return defineClass(name, buf, 0, buf.length);
			}
			catch (Exception e) {
	            throw new ClassNotFoundException(name);
			}
		}
	}

	// Any directory with large number of classes.
	private final static String CLASS_PATH = "C:\\Trash\\cp";
	
	private static ArrayList clArr = new ArrayList();
	
	/**
	 * Recursively load classes from CLASS_PATH dir and its subdirs
	 */
    static void loadClasses(File dir, String pak) throws Exception {
        File[] files = dir.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                if (files[i].isDirectory()) {
                	loadClasses(files[i], pak + files[i].getName() + ".");
                }
                else {
                	String fname = files[i].getName();
                	fname = fname.substring(0, fname.indexOf('.'));
                	SimpleClassLoader classLoader = new SimpleClassLoader(CLASS_PATH);
                	classLoader.loadClass(pak + fname);
                	
                	// uncomment following line to disallow GC finalize 
                	// SimpleClassLoader instances and free PermGen 
                	//clArr.add(classLoader);
                	
                	Thread.sleep(50); // for better visualization
                }
            }
        }
    }
    
    public static void main(String[] args) throws Exception {
        System.out.println("Start");
    	Thread.sleep(10000); // timeout to start jconsole
    	
        System.out.println("Begin classes loading");
    	loadClasses(new File(CLASS_PATH), "");
        System.out.println("Classes loading completed");
        
    	Thread.sleep(60000); // use "Perform GC" in jconsole to try to free PermGen
        System.out.println("Finish");
    }
    
}

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to