- 浏览: 227173 次
- 性别:
- 来自: 北京
最新评论
-
lzj0470:
这种方式,带来的问题很大。如:返回一个对象,然后再调用一些办法 ...
自定义classloader加密java程序 -
bushkarl:
JavaScript 胸罩尺寸计算器 -
bushkarl:
...
Ubuntu php 环境配置 -
dearsunkey:
hao !
Ubuntu php 环境配置 -
qskm:
这个怎么用呢?楼主没说清楚啊,
1、 加密的话该怎么加密?直接 ...
自定义classloader加密java程序
These errors are rather commonly seen during development phases, and even on production servers. These errors are even more annoying than others, because they do not show any stack trace. The reason for this is that a stack trace would not be of help for these errors. The code that fails with an Out Of Memory will be, in most cases, a "victim" of the problem, and not the problem itself.
Although it is very tempting to blame Tomcat on these errors, the fact is that many of them have their causes in "mistakes" in the webapps. These mistakes usually come from programming patterns and techniques perfectly legal and safe on standalone applications, but that are not correct in a managed environment like a servlet container (that is, Tomcat).
This page will maintain a list of those "well-known mistakes", so anyone experiencing these problems, or wanting to avoid them, could check their webapps and correct them.
The General Rule
The first thing to do is to set the basis for these patterns to be recognized. This way, the developer will be able to find even those mistakes that are not listed in this page, and why not, add them here :-)
An Out Of Memory can be thrown by several causes:
*
A servlet trying to load a several GBytes file into memory will surely kill the server. These kind of errors must be considered a simple bug in our program.
*
To compensate for the data your servlet tries to load, you increase the heap size so that there is no room to create the stack size for the threads that need to be created. Each thread takes 2M and in some OS's (like Debian Sarge) is not reducible with the -Xss parameter. [WWW] 1 Rule of Thumb, use no more than 1G for heap space in a 32-bit web application.
*
Deep recursive algorithms can also lead to Out Of Memory problems. In this case, the only fixes are increasing the thread stack size (-Xss), or refactoring the algorithms to reduce the depth, or the local data size per call.
*
A webapp that uses lots of libraries with many dependencies, or a server maintaining lots of webapps could exhauste the JVM PermGen space. This space is where the VM stores the classes and methods data. In those cases, the fix is to increase this size. The Sun VM has the flag -XX:MaxPermSize that allows to set its size (the default value is 64M)
*
Hard references to classes can prevent the garbage collector from reclaiming the memory allocated for them when a ClassLoader is discarded. This will occur on JSP recompilations, and webapps reloads. If these operations are common in a webapp having these kinds of problems, it will be a matter of time, until the PermGen space gets full and an Out Of Memory is thrown.
This last case is the one we intend to address here. It is directly related to the fact that the webapp is running on a managed environment, in which code changes can be commited without the application being stopped at all.
Once said this, the patterns to be included here will be those that, although being safe and legal on a standalone application, need to be refactored to make them "compatible" with the servlet container.
Threads
No other threads started in the servlet must run. Otherwise they keep local variables, their classes and the whole class loader hard referenced.
DriverManager
If you load a java.sql.Driver in your own classloader (or servlets), the driver should be removed before undeploying. Each driver is registered in DriverManager which is loaded in system classloader and references the local driver.
Enumeration<Driver> drivers = DriverManager.getDrivers();
ArrayList<Driver> driversToUnload=new ArrayList<Driver>();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
if (driver.getClass().getClassLoader().equals(getClass().getClassLoader())) {
driversToUnload.add(driver);
}
}
for (Driver driver : driversToUnload) {
DriverManager.deregisterDriver(driver);
}
The Singleton Pattern
This is a VERY used pattern in many java programs. It works safe and sound in any standalone application, and it looks something like:
public class MyClass {
private static final MyClass instance = new MyClass();
public static MyClass getInstance() {
return instance;
}
private MyClass() { }
}
The problem with this pattern is that it creates a hard reference to a class instance into the class itself. As long as this instance is not released, the class will not be unloadable. At the end, this leads to the server being unable to reclaim the space for the entire webapp class loader.
Many of the workarounds below will sacrifice some of the virtues of the original pattern, for the sake of the server integrity. It is up to the designer/developer to decide whether these sacrifices are worth the benefits.
Validation
Before you refactor your whole application, please ensure if this is really the problem. My singletons are definitely removed, but tomcat keeps crashing.
1.
Override method finalize in such a singleton class and put a System.out.println()-Message.
2.
In the constructor call several time System.gc() (because the garbage collector is a little bit lazy)
3.
Redeploy the application several times
4.
Probably you will see that the old singletons are definitely finalized which is only the case if the class loader is garbage collected.
5.
After several redeployments an out of memory occures, even with one or two "singletons" in memory.
Workaround 1: Move the class to another classloader
This workaround is for the case this class should be shared between webapps, or if the server will contain only one webapp. That is, we need to use the same instance across several webapps in the same server, or there is no need to worry about it. In this case, the class will need to be deployed on a shared classloader. This means this class must be in the shared/lib or shared/classes directory.
This way, the class will be loaded by a parent classloader, and not by the webapp classloader itself, so no resources need to be reclaimed on webapp reloadings.
This workaround may not always fit well with your code or design. In particular, care must be taken to avoid the singleton to keep references to classes loaded through the webapp classloader, because such references would prevent the classloader from being deallocated. A servlet context listener could be used to get rid of those references before the context is destroyed.
Workaround 2: Use commons-discovery
If you need to have a singleton instance for each webapp, you could use commons-discovery. This library provides a class named DiscoverSingleton that can be used to implement singletons in your webapp.
For using it, the class to be used as singleton will need to implement an interface (SPI) with the methods to be used. The following code is an example of usage of this library:
MyClass instance = DiscoverSingleton.find(MyClass.class, MyClassImpl.class.getName());
It is important, for this library to work correctly, to not keep static references to the returned instances.
Just by using this syntax, you get the following advantages:
*
Any class could be used as a singleton, as long as it implements an SPI interface.
*
Your singleton class has been converted into a replaceable component in your webapp, so you can "plug-in" a different implementation whenever you want.
But only this does not make for a workaround. The most important advantage is the DiscoverSingleton.release() method, that releases all references to instantiated singletons in the current classloader. A call to this method could be placed into a ServletContextListener, into its contextDestroyed() method.
That is, with a ServletContextListener simple implementation like the following:
public class SingletonReleaser implements ServletContextListener {
public contextInitialized(ServletContextEvent event) { }
public contextDestroyed(ServletContextEvent event) {
DiscoverSingleton.release();
}
}
we could release all cached references to the instantiated singletons. Of course, this listener should be registered on the web.xml descriptor before any other listener that could use a singleton.
Workaround 3: Use ServletContext attributes
This refactoring will work well provided the ServletContext instance is available, as a local variable or as a parameter.
It will be more efficient than using commons-discovery, but has the disadvantage of making your code depend on the web layer (ServletContext class). Anyway, I have found out that, in some cases, it is a reasonable approach.
There are many ways to do this refactoring, so I will just present one implementation that works well for me:
*
Create the following ServletContextListener:
public class SingletonFactory implements ServletContextListener {
public static final String MY_CLASS = "...";
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent event) {
ServletContext ctx = event.getServletContext();
ctx.setAttribute(MY_CLASS, new MyClass());
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent event) {
ctx.setAttribute(MY_CLASS, null);
}
/**
* Optional method for getting the MyClass singleton instance.
*/
public static MyClass getMyClassInstance(ServletContext ctx) {
return (MyClass)ctx.getAttribute(MY_CLASS);
}
}
*
Register the listener in the web.xml descriptor
*
Replace the calls to MyClass.getInstance() by:
MyClass instance = (MyClass)ctx.getAttribute(SingletonFactory.MY_CLASS);
/* or, if implemented:
MyClass instance = SingletonFactory.getMyClassInstance(ctx);
*/
Although it is very tempting to blame Tomcat on these errors, the fact is that many of them have their causes in "mistakes" in the webapps. These mistakes usually come from programming patterns and techniques perfectly legal and safe on standalone applications, but that are not correct in a managed environment like a servlet container (that is, Tomcat).
This page will maintain a list of those "well-known mistakes", so anyone experiencing these problems, or wanting to avoid them, could check their webapps and correct them.
The General Rule
The first thing to do is to set the basis for these patterns to be recognized. This way, the developer will be able to find even those mistakes that are not listed in this page, and why not, add them here :-)
An Out Of Memory can be thrown by several causes:
*
A servlet trying to load a several GBytes file into memory will surely kill the server. These kind of errors must be considered a simple bug in our program.
*
To compensate for the data your servlet tries to load, you increase the heap size so that there is no room to create the stack size for the threads that need to be created. Each thread takes 2M and in some OS's (like Debian Sarge) is not reducible with the -Xss parameter. [WWW] 1 Rule of Thumb, use no more than 1G for heap space in a 32-bit web application.
*
Deep recursive algorithms can also lead to Out Of Memory problems. In this case, the only fixes are increasing the thread stack size (-Xss), or refactoring the algorithms to reduce the depth, or the local data size per call.
*
A webapp that uses lots of libraries with many dependencies, or a server maintaining lots of webapps could exhauste the JVM PermGen space. This space is where the VM stores the classes and methods data. In those cases, the fix is to increase this size. The Sun VM has the flag -XX:MaxPermSize that allows to set its size (the default value is 64M)
*
Hard references to classes can prevent the garbage collector from reclaiming the memory allocated for them when a ClassLoader is discarded. This will occur on JSP recompilations, and webapps reloads. If these operations are common in a webapp having these kinds of problems, it will be a matter of time, until the PermGen space gets full and an Out Of Memory is thrown.
This last case is the one we intend to address here. It is directly related to the fact that the webapp is running on a managed environment, in which code changes can be commited without the application being stopped at all.
Once said this, the patterns to be included here will be those that, although being safe and legal on a standalone application, need to be refactored to make them "compatible" with the servlet container.
Threads
No other threads started in the servlet must run. Otherwise they keep local variables, their classes and the whole class loader hard referenced.
DriverManager
If you load a java.sql.Driver in your own classloader (or servlets), the driver should be removed before undeploying. Each driver is registered in DriverManager which is loaded in system classloader and references the local driver.
Enumeration<Driver> drivers = DriverManager.getDrivers();
ArrayList<Driver> driversToUnload=new ArrayList<Driver>();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
if (driver.getClass().getClassLoader().equals(getClass().getClassLoader())) {
driversToUnload.add(driver);
}
}
for (Driver driver : driversToUnload) {
DriverManager.deregisterDriver(driver);
}
The Singleton Pattern
This is a VERY used pattern in many java programs. It works safe and sound in any standalone application, and it looks something like:
public class MyClass {
private static final MyClass instance = new MyClass();
public static MyClass getInstance() {
return instance;
}
private MyClass() { }
}
The problem with this pattern is that it creates a hard reference to a class instance into the class itself. As long as this instance is not released, the class will not be unloadable. At the end, this leads to the server being unable to reclaim the space for the entire webapp class loader.
Many of the workarounds below will sacrifice some of the virtues of the original pattern, for the sake of the server integrity. It is up to the designer/developer to decide whether these sacrifices are worth the benefits.
Validation
Before you refactor your whole application, please ensure if this is really the problem. My singletons are definitely removed, but tomcat keeps crashing.
1.
Override method finalize in such a singleton class and put a System.out.println()-Message.
2.
In the constructor call several time System.gc() (because the garbage collector is a little bit lazy)
3.
Redeploy the application several times
4.
Probably you will see that the old singletons are definitely finalized which is only the case if the class loader is garbage collected.
5.
After several redeployments an out of memory occures, even with one or two "singletons" in memory.
Workaround 1: Move the class to another classloader
This workaround is for the case this class should be shared between webapps, or if the server will contain only one webapp. That is, we need to use the same instance across several webapps in the same server, or there is no need to worry about it. In this case, the class will need to be deployed on a shared classloader. This means this class must be in the shared/lib or shared/classes directory.
This way, the class will be loaded by a parent classloader, and not by the webapp classloader itself, so no resources need to be reclaimed on webapp reloadings.
This workaround may not always fit well with your code or design. In particular, care must be taken to avoid the singleton to keep references to classes loaded through the webapp classloader, because such references would prevent the classloader from being deallocated. A servlet context listener could be used to get rid of those references before the context is destroyed.
Workaround 2: Use commons-discovery
If you need to have a singleton instance for each webapp, you could use commons-discovery. This library provides a class named DiscoverSingleton that can be used to implement singletons in your webapp.
For using it, the class to be used as singleton will need to implement an interface (SPI) with the methods to be used. The following code is an example of usage of this library:
MyClass instance = DiscoverSingleton.find(MyClass.class, MyClassImpl.class.getName());
It is important, for this library to work correctly, to not keep static references to the returned instances.
Just by using this syntax, you get the following advantages:
*
Any class could be used as a singleton, as long as it implements an SPI interface.
*
Your singleton class has been converted into a replaceable component in your webapp, so you can "plug-in" a different implementation whenever you want.
But only this does not make for a workaround. The most important advantage is the DiscoverSingleton.release() method, that releases all references to instantiated singletons in the current classloader. A call to this method could be placed into a ServletContextListener, into its contextDestroyed() method.
That is, with a ServletContextListener simple implementation like the following:
public class SingletonReleaser implements ServletContextListener {
public contextInitialized(ServletContextEvent event) { }
public contextDestroyed(ServletContextEvent event) {
DiscoverSingleton.release();
}
}
we could release all cached references to the instantiated singletons. Of course, this listener should be registered on the web.xml descriptor before any other listener that could use a singleton.
Workaround 3: Use ServletContext attributes
This refactoring will work well provided the ServletContext instance is available, as a local variable or as a parameter.
It will be more efficient than using commons-discovery, but has the disadvantage of making your code depend on the web layer (ServletContext class). Anyway, I have found out that, in some cases, it is a reasonable approach.
There are many ways to do this refactoring, so I will just present one implementation that works well for me:
*
Create the following ServletContextListener:
public class SingletonFactory implements ServletContextListener {
public static final String MY_CLASS = "...";
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent event) {
ServletContext ctx = event.getServletContext();
ctx.setAttribute(MY_CLASS, new MyClass());
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent event) {
ctx.setAttribute(MY_CLASS, null);
}
/**
* Optional method for getting the MyClass singleton instance.
*/
public static MyClass getMyClassInstance(ServletContext ctx) {
return (MyClass)ctx.getAttribute(MY_CLASS);
}
}
*
Register the listener in the web.xml descriptor
*
Replace the calls to MyClass.getInstance() by:
MyClass instance = (MyClass)ctx.getAttribute(SingletonFactory.MY_CLASS);
/* or, if implemented:
MyClass instance = SingletonFactory.getMyClassInstance(ctx);
*/
发表评论
-
男士常见肌肤问题及针对方案
2008-06-17 12:54 1335问题一:皮肤就象个大油田,常常看上去油光光的,可是感觉居然还是 ... -
做软件外包就像农民种地一样
2008-06-12 13:23 2209中关 村软件园里,坐落 ... -
MDA-ZZ
2008-05-10 20:20 1236MDA(Model Driven Architectur ... -
男人最帅的39个瞬间 =共勉~
2008-04-20 02:18 10201.不说话的时候。 沉默 ... -
把你的DV作品送到嘎纳去吧
2008-04-08 17:26 1039可能在大多数人眼中, ... -
意大利作曲家维瓦尔第
2008-04-03 10:57 1031意大利作曲家。 167 ... -
NGOSS:下一代网络运营支撑系统
2008-03-27 23:19 1178摘要:首先介绍了NGOSS ... -
给女孩的话:当他不再爱你的时候
2008-03-26 20:16 1309当他不再爱你的时候,不要再给他打电话。你的一句我想你,只能换来 ... -
服务发现ZZ
2008-03-24 10:08 994服务发现:采用自上而 ... -
.NET平台下几种SOCKET模型的简要性能供参考ZZZ
2008-03-17 19:57 1364这个内容在cnblogs中也讨论过很多次了,这两天大概看了一些 ... -
牛仔裤你一定要知道的16条ZZZ
2008-03-06 09:10 9501买牛仔裤,裤腰处留出3 ... -
2007浙江高考满分作文之一行走在消逝中
2008-02-11 12:24 1795——loli有三好,身娇 ... -
DOS here
2008-02-02 18:18 1238挺方便的。代码记在这。 引用Windows Registry ... -
UDP tracker protocol
2008-01-29 11:43 2061留存。。以作参考。。 原文:http://xbtt.sourc ... -
IP多播【转】
2008-01-28 21:53 1923IP多播(也称多址广播 ... -
Why Ruby on Rails won't become mainstream【转】
2008-01-28 12:43 1252在tss看到的,原帖地址是: http://beust.com ... -
比較Java和C++的總體擁有成本
2008-01-18 13:28 1122BEA公司的白皮書,比較了Java和C++的總體擁有成本 -
人生能有5次就好了
2008-01-17 19:59 1507有好多想做的事情 我想当学校的老师... 也想当宇宙飞 ... -
BGP协议【转载自51cto】
2008-01-16 14:21 1127刚才看streaming的paper,发现自己欠缺的太多了。 ... -
大学的脾气有多大【转自豆瓣九点】
2008-01-13 16:16 1263大学的“脾气”有多大 ...
相关推荐
Experience Report: A Characteristic Study on Out of Memory Errors in Distributed Data-Parallel Applications
Out of Bag Errors & Cross Validation - how good of a fit did the machine learning algorithm make? Gini Criteria & Entropy Criteria - how to tell which split on a decision tree is best among many ...
The usual implementation of malloc and free are unforgiving to errors in their callers' code, including cases where the programmer overflows an array, forgets to free memory, or frees a memory block ...
### 如何避免常见错误并使程序更高效 在软件开发过程中,特别是在Symbian平台上的应用开发中,遵循良好的编程实践对于确保程序的稳定性和效率至关重要。本文将根据提供的文件内容,详细介绍如何避免常见的错误,并...
of how the memory cells are laid out on the chip. In addition there is a never ending number of possible chip layouts for different chip types and manufacturers making this strategy impractical. ...
the main data containers (i.e., lists, tuples, and dictionaries) and how you use them to store and manipulate your data, as well as how to deal with dates, as dates often appear in business analysis....
While most developers today use object-oriented languages, the full power of objects is available only to those with a deep understanding of the object paradigm. How to Use Objects will help you gain ...
You’ll discover what goes into creating a program, as well as how to put the various pieces together, deal with standard programming challenges, handle debugging, and make it all work. Details the ...
printf("Number of letters in word: "); scanf("%d", &size1); // 注意这里应该添加分号 printf("Number of integers: "); scanf("%d", &size2); // 同上 str = (char *) malloc(sizeof(char) * size1); ...
and the JSSE for encryption and authentication The ways in which padding mechanisms work in ciphers and how to spot and fix typical errors An understanding of how authentication mechanisms are ...
Troubleshooting out of memory errors, Java level deadlocks, and HotSpot VM crashes Extending the Serviceability Agent, and using the Plugin for VisualVM Mastering useful HotSpot VM command line ...
1、创建vue项目后安装less,执行 npm install less less-loader –save-dev 下载版本为:less-loader@6.1.0 , less@3.11.3,重启服务报错,报错信息如下: 2、报错原因 less 本版太高需要降低版本,执行代码 ...
While the advice and information in this book are believed to be true and accurate at the date of publication, neither the authors nor theeditors nor the publisher can accept any legal responsibility ...
You’ve learned the essentials of working with LLDB’s Python module, as well as how to correct any errors using Python’s PDB debugging module. Now you’ll explore the main players within the lldb ...
Any certification or other statement of compliance with any health or safety-related information in this document shall not be attributable to PMI and is solely the responsibility of the certifier or...
How do you take your data analysis skills beyond Excel to the next level? By learning just enough Python to get stuff done. This hands-on guide shows non-programmers like you how to process ...
- **Breaking Out of Loops**: How to prematurely exit a loop using the `break` statement. - **Going Back to the Top of a Loop**: Explanation of the `continue` statement, which skips the rest of the ...
- Enhanced the mechanism to report memory hardware errors in the Memory torture test. Release 5.3 build 1033 WIN32 release 1 October 2008 - Changes to correct a BurnInTest crash problem on some ...