Tomcat内存溢出(java.lang.OutOfMemoryError: PermGen space)的解决办法

本文介绍了当Tomcat启动遇到PermGen错误时的解决方法。提供了三种不同场景下的解决方案,包括通过Eclipse配置、修改Windows服务设置及调整命令行启动参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Tomcat启动时报如下错误:
   
java.lang.OutOfMemoryError: PermGen space


解决办法:
   配置相关内存大小。其中按照启动tomcat的不同方式,分如下三种情况
   a):如果是eclipse的tomcat插件启动tomcat,在“window”菜单-“Preferences”-“Tomcat”-“JVM Settings”中添加JVM参数如下即可:
       -Xms128M -Xmx512M -XX:PermSize=128M -XX:MaxPermSize=256M

   b):如果tomcat是安装为windows服务,从服务启动,则打开注册表编辑器,定位到:HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Procrun 2.0\tomcat6\Parameters\Java(Win7 X64系统则位于HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Apache Software Foundation\Procrun 2.0\tomcat6\Parameters\Java)
       双击右侧窗口的“Options”键值,添加如下行:
       -XX:PermSize=128M
       -XX:MaxNewSize=256m
       -XX:MaxPermSize=256m

   c):如果是命令行方式启动tomcat,则修改脚本文件(Windows下为catalina.bat,Linux下为catalina.sh),同样的方式,为JAVA_OPTS变量添加上述参数即可
<think>我们正在处理关于Druid数据源关闭时出现内存溢出OutOfMemoryError:PermGenspace)的问题。根据用户的问题,重点在于如何解决DruidDataSource在调用destroy方法(即close方法)时出现的PermGen空间内存溢出问题。首先,我们需要理解PermGen(永久代)是Java7及之前版本中用于存放类元数据、静态变量、常量池等数据的内存区域。在Java8及以后,PermGen被元空间(Metaspace)取代。因此,如果出现PermGen溢出,说明在类卸载方面存在问题,可能存在类加载器泄漏。在Druid数据源关闭时,可能由于某些原因导致类加载器无法被垃圾回收,从而使得PermGen空间被占满。常见的场景是应用在多次重新部署时,每次部署都会加载新的类到PermGen,而旧的类没有被卸载,最终导致PermGen溢出。针对此问题,我们可以从以下几个方面进行解决:###1.升级JVM版本如果还在使用Java7或更早版本,考虑升级到Java8或更高版本,因为Java8使用元空间替代了PermGen。元空间使用本地内存,且默认情况下没有大小限制(但受系统内存限制),可以通过参数调整。元空间也会进行垃圾回收,减少了永久代溢出的可能性。###2.调整JVM参数如果使用Java7或更早版本:-增加PermGen空间大小:```bash-XX:PermSize=256m-XX:MaxPermSize=512m```如果使用Java8及以上版本,可以调整元空间大小(虽然问题可能由元空间引起,但调整参数可能缓解):```bash-XX:MetaspaceSize=256m-XX:MaxMetaspaceSize=512m```###3.检查并修复类加载器泄漏在应用关闭时,确保所有资源都被正确释放,尤其是线程池、连接池等。对于Druid数据源,除了调用`close`方法外,还要确保没有其他引用持有该数据源或其相关的类加载器。在Spring框架中,如果配置了Druid数据源,通常会在Spring容器关闭时调用destroy方法。确保你的Spring配置正确,例如:```xml<beanid="dataSource"class="com.alibaba.druid.pool.DruidDataSource"init-method="init"destroy-method="close">...</bean>```或者使用注解方式:```java@Bean(destroyMethod="close")publicDataSourcedataSource(){DruidDataSourcedataSource=newDruidDataSource();...returndataSource;}```###4.检查第三方库的兼容性确保使用的Druid版本与你的应用环境(如Spring、JDK等)兼容。有时,特定版本的Druid可能存在内存泄漏问题,尝试升级Druid到最新稳定版本。###5.分析内存溢出原因使用内存分析工具(如jmap、jvisualvm、EclipseMAT)来获取内存转储(heapdump),然后分析PermGen中的对象,特别是哪些类加载器没有被卸载,以及为什么没有被卸载。###6.监控与日志开启Druid的监控和日志功能,观察连接池的状态,特别是在关闭时的行为。Druid提供了监控页面和日志输出,可以帮助定位问题。###7.使用Druid的内置防御机制Druid提供了一些防御性的参数,例如`removeAbandoned`和`removeAbandonedTimeout`,这些参数用于回收被遗弃的连接。虽然主要针对连接泄漏,但有时可能间接影响类加载器的回收。###8.在应用停止时显式清理如果上述方法无效,可以尝试在应用停止时强制清理Druid数据源相关的资源。例如,在Servlet的`destroy()`方法中,或者在Spring的`DisposableBean`中编写清理逻辑。###9.检查是否有其他资源泄漏除了类加载器泄漏外,还可能有其他资源没有关闭,如网络连接、文件句柄等。这些资源也可能间接导致类加载器无法被卸载。###10.使用类加载器泄漏检测工具使用专门的类加载器泄漏检测工具(如ClassLoaderLeakPrevention)来帮助发现和预防类加载器泄漏。§§相关问题§§1.Java8及以上版本中,如何监控和调整元空间内存?2.如何通过日志和监控工具分析Druid连接池的关闭过程?3.在SpringBoot中如何正确配置Druid数据源的销毁方法?4.如何获取和分析内存转储(heapdump)来定位类加载器泄漏?5.除了Druid,还有哪些常见的类加载器泄漏场景和解决方法?</think> ### 解决 Druid 数据源关闭时的内存溢出问题 当 DruidDataSource 调用 `destroy` 方法 (`close()`) 时出现 `OutOfMemoryError: PermGen space` 错误,通常是由于类加载器未正确释放导致永久代内存泄漏。以下是系统级的解决方案: #### 1. 根本原因分析 - **永久代(PermGen)泄漏**:Druid 数据源关闭时,其关联的类加载器(如 JDBC 驱动类)未被垃圾回收[^1] - **类加载器未释放**:Web 容器(Tomcat)热部署时,旧版本的类未卸载 - **JDBC 驱动注册问题**:部分 JDBC 驱动(如 MySQL)会将自己注册到 `DriverManager` 导致引用残留 #### 2. 解决方案(代码级实现) ```java // 正确的销毁方法示例(Spring Boot 配置) @Bean(destroyMethod = "close") public DataSource dataSource() { DruidDataSource ds = new DruidDataSource(); ds.setUrl("jdbc:mysql://localhost/db"); ds.setDriverClassName("com.mysql.jdbc.Driver"); // 关键:手动解除驱动注册 ds.setDriverClassLoader(Thread.currentThread().getContextClassLoader()); return ds; } ``` #### 3. JVM 参数优化 ```bash # Java 7 及更早版本(调整PermGen) -XX:PermSize=256m -XX:MaxPermSize=512m # Java 8+(改用Metaspace) -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m ``` #### 4. 强制卸载方案 在应用关闭时手动执行: ```java // 1. 强制清理 DriverManager java.util.Collections.list(DriverManager.getDrivers()).forEach(driver -> { try { DriverManager.deregisterDriver(driver); } catch (SQLException ignored) {} }); // 2. 清理线程上下文类加载器 Thread.currentThread().setContextClassLoader(null); ``` #### 5. Druid 版本升级 使用 Druid 1.2.8+ 版本,其内建修复方案: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.16</version> <!-- 修复内存泄漏的版本 --> </dependency> ``` #### 验证步骤 1. 部署后触发应用停止 2. 使用 `jmap -permstat <pid>` 监控 PermGen 状态 3. 观察 GC 日志是否显示类卸载: ```log [Unloading class sun.reflect.GeneratedMethodAccessor123] ``` > **重要提示**:使用热部署工具(如 JRebel)可能导致此问题加剧,建议在正式环境禁用[^1]
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值