java.lang.OutOfMemoryError: PermGen space eclipse报错及其解决办法

本文介绍了如何解决Java应用程序中出现的PermGen内存溢出问题。提供了针对不同环境(Windows和Linux)及Eclipse IDE的具体配置方法。

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

今天运行项目遇到一个问题,就是java.lang.OutOfMemoryError: PermGen space。翻译是内存溢出,是由于jvm内存不够引起的错误。
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域OutOfMemoryError: PermGen space从表面上看就是内存益出,解决方法也一定是加大内存。

  1. 在运行较大的项目
  2. 一次性从数据库查询数据较多
  3. 代码存在死循环,使用递归都有可能引起这个错误。

尝试了修改tomcat下Catalina.bat文件,在里面设置内存的大小,并没什么作用。然后查到原因是因为eclipse在运行项目会忽略掉Catalina.bat中设置的参数,如果使用tomcat启动的,这个方法应该是好用的。

1、windows环境下解决方案

在Catalina.bat文件开头加

set JAVA_OPTS=-server -Xms256m -Xmx256m -XX:PermSize=512M -XX:MaxPermSize=512m -XX:-UseGCOverheadLimit %JAVA_OPTS%

2、linux环境下解决方案

修改Catalina.sh文件,在cygwin=false之前加

AVA_OPTS="-server -Xmx256m -Xms256m -XX:PermSize=512M -XX:MaxPermSize=5"

3、eclipse下解决方法

选中运行的项目,右键选择run ——> run configuration ——> VM arguements 在VM arguements中最下面添加

-Xms256m -Xmx512m -XX:MaxNewSize=256m -XX:MaxPermSize=256m

设置最小内存和最大内存。
这里写图片描述

<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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值