Re: Jsp class loader issue in Tomcat 7
Konstantin, Does it means it's a bad thing to use jsp as templating inside a webapp? And it's normal that it breaks *other* applications but not the application itself? I would expect the opposite scenario. Thanks and regards Trung 2012/11/15 Konstantin Kolinko knst.koli...@gmail.com 2012/11/14 Christopher Schultz ch...@christopherschultz.net: Do you have any idea why old jasper-compiler (used inside an application) provoke errors to other applications? Is it a bug? Or is there some additional config to make it works? Oh, this breaks *other* applications? There may be some weirdness, here, because Tomcat internals might be polluted by classes loaded from a particular webapp. That definitely shouldn't happen if we can help it. It is a feature. If your webapps are bad citizens and do stupid things or you need protection from them, run with SecurityManager being enabled. Unless you run with SecurityManager, there is no protection against any webapp messing up with Tomcat internals, Java internals, or messing up with your operating system as a whole (limited only by the rights that tomcat user has). Note that if you run with SecurityManager, you have to pay the performance price for all those little checks that it does. Best regards, Konstantin Kolinko - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: Jsp class loader issue in Tomcat 7
2012/11/15 Duc Trung TRAN ductrung.t...@gmail.com: Konstantin, Does it means it's a bad thing to use jsp as templating inside a webapp? It is bad thing to bundle Tomcat components inside web applications. You should never do that. [1] should explain why. [1] and [2] should explain why things are different between 5.5 and 6.07.0. [1] http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html [2] http://tomcat.apache.org/migration-6.html#Shared_libraries And it's normal that it breaks *other* applications but not the application itself? I would expect the opposite scenario. Use a SecurityManager and you will get that opposite scenario. In 5.5 the server components are more isolated from the web applications, due to having a separate server classloader. It was considered a waste, because it does not provide any security by itself unless you really run with a SecurityManager. Note that in Tomcat 6 7 (and in Tomcat 5.5 in webapps that have Context privileged=true) the server classes are directly visible from the webapp. There is no need to bundle such jars in your application. 2012/11/15 Konstantin Kolinko knst.koli...@gmail.com 2012/11/14 Christopher Schultz ch...@christopherschultz.net: Do you have any idea why old jasper-compiler (used inside an application) provoke errors to other applications? Is it a bug? Or is there some additional config to make it works? Oh, this breaks *other* applications? There may be some weirdness, here, because Tomcat internals might be polluted by classes loaded from a particular webapp. That definitely shouldn't happen if we can help it. It is a feature. If your webapps are bad citizens and do stupid things or you need protection from them, run with SecurityManager being enabled. Unless you run with SecurityManager, there is no protection against any webapp messing up with Tomcat internals, Java internals, or messing up with your operating system as a whole (limited only by the rights that tomcat user has). Note that if you run with SecurityManager, you have to pay the performance price for all those little checks that it does. Best regards, Konstantin Kolinko - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: Jsp class loader issue in Tomcat 7
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Trung, On 11/14/12 10:18 AM, Duc Trung TRAN wrote: We are trying to migrate Tomcat 5.5 to Tomcat 7. And We have issues in an old application which make use of JspC class. In fact, this application has an internal jsp templating and use JspC to generate java files from templates. So it has an old version of jasper-compiler.jar in it WEB-INF/lib. Stop right there. You can't use an older JSP compiler with a newer version of Tomcat: the JSP compiler references all kinds of Tomcat internal stuff that isn't compatible across versions (sometimes even across minor releases like x.y.1). You will have to update your compiler JAR in order for any of this to work. In Tomcat 7, this application works but not all other applications. There are errors as below. SEVERE: Servlet.service() for servlet [jsp] in context with path [] threw exception [java.lang.AbstractMethodError: Yep, that's the kind of stuff that will happen to you if you have mismatched versions. I suppose there is a classloader issue when we use old version of jasper compiler (???). Perhaps, but the best thing to do would be to upgrade. Because when we remove the old jasper-compiler.jar, all other applications work but not the former :(. It reference indeed an old method (JspC.setLog) which is removed in the new version of JspC. And we don't have the source (only binary) of the application to make change. How big is the application? Perhaps you could decompile the class that calls JspC.setLog, modify it, recompile it and put it back into your application. You could even do it as a separate JAR file earlier in the CLASSPATH. The best way to do that, actually, is to put the patched version into WEB-INF/classes because those take precedence over classes in WEB-INF/lib/*.jar. Do you have any idea why old jasper-compiler (used inside an application) provoke errors to other applications? Is it a bug? Or is there some additional config to make it works? Oh, this breaks *other* applications? There may be some weirdness, here, because Tomcat internals might be polluted by classes loaded from a particular webapp. That definitely shouldn't happen if we can help it. - -chris -BEGIN PGP SIGNATURE- Version: GnuPG/MacGPG2 v2.0.17 (Darwin) Comment: GPGTools - http://gpgtools.org Comment: Using GnuPG with Mozilla - http://www.enigmail.net/ iEYEARECAAYFAlCj2H4ACgkQ9CaO5/Lv0PDbTwCggwSbRl3hoD/4jLkk2RvVEDry MYMAoKVBo0Xrsb/BIR6wVj+uVheO2llH =UMXY -END PGP SIGNATURE- - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: Jsp class loader issue in Tomcat 7
2012/11/14 Christopher Schultz ch...@christopherschultz.net: Do you have any idea why old jasper-compiler (used inside an application) provoke errors to other applications? Is it a bug? Or is there some additional config to make it works? Oh, this breaks *other* applications? There may be some weirdness, here, because Tomcat internals might be polluted by classes loaded from a particular webapp. That definitely shouldn't happen if we can help it. It is a feature. If your webapps are bad citizens and do stupid things or you need protection from them, run with SecurityManager being enabled. Unless you run with SecurityManager, there is no protection against any webapp messing up with Tomcat internals, Java internals, or messing up with your operating system as a whole (limited only by the rights that tomcat user has). Note that if you run with SecurityManager, you have to pay the performance price for all those little checks that it does. Best regards, Konstantin Kolinko - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: JSP class loader
Chris, As article says, container drops all reference to classloader during web-app undeploy. This allows GC to remove classloader and free PermGen. In our system, JSP deployed inside web-app without web-app redeply. So references to ClassLoader aren't dropped. Aah, I didn't realize that you were doing this. So, you basically maintain your own versioning for each JSP? Yes. New JSP deployed to different directory. If I request that a JSP job be run several times, each run gets its own class compiled and loaded? I think yes. Obsolete classes removed only on web-app undeploy. This seems a little kludgey. You are you using JSP as a batch processing platform? What do you mean batch processing? I see, threre are two possible ways for now: modify jsp servlet as I going to before or create web-app for each business process and redeploy it when new JSP arrived. I realize that you are probably required to work within the boundaries of a pre-existing system, Our system is the platform for other applications (as Tomcat it-self). Therefore, it can't be pre-existed. -- Nikita - To start a new topic, e-mail: users@tomcat.apache.org To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
RE: JSP class loader
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(1); // timeout to start jconsole System.out.println(Begin classes loading); loadClasses(new File(CLASS_PATH), ); System.out.println(Classes loading completed);
Re: JSP class loader
Nikita, 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. I read through your ClassLoader. It doesn't look like it will compile, but I'll assume that it was just a copy/paste problem into your message. I'm not sure what your ClassLoader does differently than any other ClassLoader; what have you added? If you haven't changed anything, then it's possible that your classloaders are not being GC'd: http://opensource2.atlassian.com/confluence/spring/pages/viewpage.action?pageId=2669 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. Do you use your own (hand-written) ClassLoader for the scriptlets, or one that comes with the JDK? Someone with more knowledge of Tomcat's internal workings would have to confirm the behavior of Tomcat when a JSP changes and must be recompiled: is the ClassLoader for all JSPs discarded, or is there a separate ClassLoader for each JSP? I'm guessing that the ClassLoader itself is not your problem, but other objects retaining references to objects and classes loaded by it. I encourage you to read through the article I included above to see if any of the known offenders could possibly be affecting you -- particularly the introspection caches. All JSP classes are loaded by the one Tomcat classloader and can't be unloaded from memory. This is the problem. I think they /can/ be unloaded from memory, but again, I'm not exactly sure. This might be a question to ask on the Tomcat developer mailing list. If Tomcat's ClassLoader really does not discard old compiled JSP classes, then you really might have to hack the JSP compiler and/or loader (if they are different) to separate each JSP into its own ClassLoader. I'm very interested to see how this turns out. -chris signature.asc Description: OpenPGP digital signature
RE: JSP class loader
Chris, 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. I read through your ClassLoader. It doesn't look like it will compile, Why? It were compiled and run on my PC. but I'll assume that it was just a copy/paste problem into your message. I'm not sure what your ClassLoader does differently than any other ClassLoader; what have you added? If you haven't changed anything, then it's possible that your classloaders are not being GC'd: http://opensource2.atlassian.com/confluence/spring/pages/viewpage.action? pageId=2669 As article says, container drops all reference to classloader during web-app undeploy. This allows GC to remove classloader and free PermGen. In our system, JSP deployed inside web-app without web-app redeply. So references to ClassLoader aren't dropped. It is not possible to redeploy web-app, when new JSP arrived, however may be we can create separate web-apps for each business process, and redeploy it. I will think about it... 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. Do you use your own (hand-written) ClassLoader for the scriptlets, or one that comes with the JDK? Yes. It is our own classloader. Someone with more knowledge of Tomcat's internal workings would have to confirm the behavior of Tomcat when a JSP changes and must be recompiled: is the ClassLoader for all JSPs discarded, or is there a separate ClassLoader for each JSP? Looks like Tomcat create classloader for each web-app. I'm guessing that the ClassLoader itself is not your problem, but other objects retaining references to objects and classes loaded by it. I encourage you to read through the article I included above to see if any of the known offenders could possibly be affecting you -- particularly the introspection caches. All JSP classes are loaded by the one Tomcat classloader and can't be unloaded from memory. This is the problem. I think they /can/ be unloaded from memory, but again, I'm not exactly sure. This might be a question to ask on the Tomcat developer mailing list. If Tomcat's ClassLoader really does not discard old compiled JSP classes, Looks like these classes will be removed from PermGen with classloader after web-app undeploy. then you really might have to hack the JSP compiler and/or loader (if they are different) to separate each JSP into its own ClassLoader. I'm very interested to see how this turns out. I see, threre are two possible ways for now: modify jsp servlet as I going to before or create web-app for each business process and redeploy it when new JSP arrived. -- Nikita - To start a new topic, e-mail: users@tomcat.apache.org To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: JSP class loader
Nikita, I read through your ClassLoader. It doesn't look like it will compile, Why? It were compiled and run on my PC. Oh, sorry. The indentation was a little funny and I didn't see the method signature for private byte loadClassData(File f). Never mind. I'm not sure what your ClassLoader does differently than any other ClassLoader; what have you added? If you haven't changed anything, then it's possible that your classloaders are not being GC'd: http://opensource2.atlassian.com/confluence/spring/pages/viewpage.action? pageId=2669 As article says, container drops all reference to classloader during web-app undeploy. This allows GC to remove classloader and free PermGen. In our system, JSP deployed inside web-app without web-app redeply. So references to ClassLoader aren't dropped. Aah, I didn't realize that you were doing this. So, you basically maintain your own versioning for each JSP? If I request that a JSP job be run several times, each run gets its own class compiled and loaded? This seems a little kludgey. You are you using JSP as a batch processing platform? I see, threre are two possible ways for now: modify jsp servlet as I going to before or create web-app for each business process and redeploy it when new JSP arrived. I realize that you are probably required to work within the boundaries of a pre-existing system, but I'm really curious to see why you are using this platform to essentially perform batch processing. -chris signature.asc Description: OpenPGP digital signature
Re: JSP class loader
Nikita, 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? That doesn't seem likely. After tomcat compiles your JSP, it loads the resulting class and executes it like a servlet. 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. Is this the behavior you are describing? If so, then you can't fix the problem by writing your own JSP compiler and/or ClassLoader. 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. -chris signature.asc Description: OpenPGP digital signature