最近,我在我的web应用程序中遇到了这个错误:
java.lang.OutOfMemoryError:永久生成空间
它是一个典型的Hibernate/JPA + IceFaces/JSF应用程序,运行在Tomcat 6和JDK 1.6上。 显然,这可能发生在重新部署应用程序几次之后。
是什么原因导致的,如何避免呢? 我该如何解决这个问题?
最近,我在我的web应用程序中遇到了这个错误:
java.lang.OutOfMemoryError:永久生成空间
它是一个典型的Hibernate/JPA + IceFaces/JSF应用程序,运行在Tomcat 6和JDK 1.6上。 显然,这可能发生在重新部署应用程序几次之后。
是什么原因导致的,如何避免呢? 我该如何解决这个问题?
当前回答
我尝试了几个答案,最终完成工作的唯一一件事是在pom中的编译器插件的配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<fork>true</fork>
<meminitial>128m</meminitial>
<maxmem>512m</maxmem>
<source>1.6</source>
<target>1.6</target>
<!-- prevent PermGen space out of memory exception -->
<!-- <argLine>-Xmx512m -XX:MaxPermSize=512m</argLine> -->
</configuration>
</plugin>
希望这一点能有所帮助。
其他回答
为Tomcat分配更多内存不是正确的解决方案。
正确的解决方案是在销毁和重新创建上下文(热部署)之后进行清理。解决方案是停止内存泄漏。
如果Tomcat/Webapp服务器告诉您未能注销驱动程序(JDBC),那么请注销它们。这将阻止内存泄漏。
您可以创建一个ServletContextListener并在web.xml中配置它。下面是一个示例ServletContextListener:
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.log4j.Logger;
import com.mysql.jdbc.AbandonedConnectionCleanupThread;
/**
*
* @author alejandro.tkachuk / calculistik.com
*
*/
public class AppContextListener implements ServletContextListener {
private static final Logger logger = Logger.getLogger(AppContextListener.class);
@Override
public void contextInitialized(ServletContextEvent arg0) {
logger.info("AppContextListener started");
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
logger.info("AppContextListener destroyed");
// manually unregister the JDBC drivers
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
logger.info(String.format("Unregistering jdbc driver: %s", driver));
} catch (SQLException e) {
logger.info(String.format("Error unregistering driver %s", driver), e);
}
}
// manually shutdown clean up threads
try {
AbandonedConnectionCleanupThread.shutdown();
logger.info("Shutting down AbandonedConnectionCleanupThread");
} catch (InterruptedException e) {
logger.warn("SEVERE problem shutting down AbandonedConnectionCleanupThread: ", e);
e.printStackTrace();
}
}
}
然后在web.xml中进行配置:
<listener>
<listener-class>
com.calculistik.mediweb.context.AppContextListener
</listener-class>
</listener>
解决方案是在启动Tomcat时将这些标志添加到JVM命令行:
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
您可以通过关闭tomcat服务,然后进入tomcat /bin目录并运行tomcat6w.exe来做到这一点。在“Java”选项卡下,将参数添加到“Java选项”框。单击“确定”,然后重新启动服务。
如果你得到一个错误,指定的服务不存在作为一个安装的服务,你应该运行:
tomcat6w //ES//servicename
其中servicename是在services.msc
来源:orx对Eric敏捷回答的评论。
内存的配置取决于应用程序的性质。
你在做什么?
处理的交易数量是多少?
加载了多少数据?
etc.
etc.
etc
也许你可以配置你的应用程序,并开始清理一些模块从你的应用程序。
显然,这可能发生在重新部署应用程序几次之后
Tomcat采用热部署,但占用内存。试着每隔一段时间重新启动容器。此外,您还需要知道在生产模式下运行所需的内存量,这似乎是进行研究的好时机。
我有一个Hibernate+Eclipse RCP的组合,尝试使用-XX:MaxPermSize=512m和-XX:PermSize=512m,它似乎对我有用。
另外,如果你在你的webapp中使用log4j,检查log4j文档中的这段。
似乎如果你正在使用propertyconfiguration . configureandwatch ("log4j.properties"),当你取消部署你的web应用程序时,你会导致内存泄漏。