为什么Oracle驱动在Java中会导致PermGen内存溢出_确保在Web应用关闭时卸载JDBC驱动

星枫姑娘_7166

星枫姑娘_7166

2026-05-28

490人浏览

原创

oracle jdbc驱动不卸载会导致permgen oom,本质是classloader泄漏:oracledriver被webappclassloader加载后注册到由bootstrapclassloader管理的drivermanager中,形成反向引用链,使类加载器无法回收,其加载的类永久驻留permgen。

oracle jdbc驱动在web应用中不卸载,会直接导致permgen oom——这不是配置不够的问题,而是类加载器泄漏(classloader leak)的典型表现。hotspot jvm 7/8 的 permgen 区域无法回收被 webappclassloader 加载的 oracle.jdbc.driver.oracledriver 及其关联的类(如 oracle.sql.*、oracle.net.*),只要该类加载器还被引用,整块类元数据就永远驻留内存。

为什么Web容器重启后PermGen持续增长

每次热部署或应用重加载,Tomcat 会新建一个 WebAppClassLoader 实例去加载你的应用,包括 ojdbc.jar 中的类。但 Oracle 驱动在初始化时会向 java.sql.DriverManager 注册自己(调用 DriverManager.registerDriver(new OracleDriver())),而 DriverManager 是由系统类加载器(BootstrapClassLoader)加载的,它持有对所有已注册 Driver 实例的强引用。由于 OracleDriver 实例由 WebAppClassLoader 加载,系统类加载器 → Driver 实例 → WebAppClassLoader 形成一条“反向引用链”,导致该类加载器无法被 GC 回收,其加载的所有类(含大量内部类、常量池项)永久滞留 PermGen。

  • 现象:连续 5 次 redeploy 后,jstat -permstat 显示已加载类数量翻倍,java.lang.OutOfMemoryError: PermGen space 几乎必然发生
  • 关键点:DriverManager.deregisterDriver() 不会自动触发;JDBC 4.0+ 的 ServiceLoader 自动注册机制(META-INF/services/java.sql.Driver)同样不会自动清理
  • 验证方式:用 jmap -histo:live <pid></pid> 查看 oracle. 开头的类实例数是否随 redeploy 累积

如何在Web应用关闭时强制卸载Oracle驱动

必须在 ServletContextListener.contextDestroyed() 或 Spring 的 DisposableBean.destroy() 中显式反注册,并清除线程上下文类加载器残留。仅靠 System.setProperty("jdbc.drivers", "") 无效。

java-enterprise
java-enterprise

Java企业开发专家,专注于Spring Boot、微服务架构和JVM优化。适用于:Java语言掌握、

下载
  • 调用 DriverManager.deregisterDriver(DriverManager.getDrivers().nextElement()) —— 但要注意遍历需用 Enumeration<driver></driver> 并捕获 SQLException,因为某些驱动可能已失效
  • 手动清空 DriverManager 内部的 CopyOnWriteArrayList<driverinfo></driverinfo>(JDK 7/8)需反射访问,不推荐;稳妥做法是只处理已知 Oracle 驱动实例
  • 更可靠的做法:获取当前 WebAppClassLoader 加载的所有 Driver 子类实例,逐个 deregister。示例代码核心逻辑:
for (Enumeration<driver> drivers = DriverManager.getDrivers(); drivers.hasMoreElements();) {
    Driver driver = drivers.nextElement();
    if (driver.getClass().getName().startsWith("oracle.") &&
        driver.getClass().getClassLoader() == getClass().getClassLoader()) {
        try { DriverManager.deregisterDriver(driver); }
        catch (SQLException ignored) {}
    }
}</driver>
  • 额外动作:调用 Thread.currentThread().setContextClassLoader(null),防止线程池中存活线程持有所属 WebApp 的类加载器

比卸载更根本的规避方案

PermGen 在 JDK 8 中已被 Metaspace 替代,但问题本质未变——类加载器泄漏依然会导致 Metaspace OOM(错误信息变为 java.lang.OutOfMemoryError: Metaspace)。因此,不能只依赖升级 JDK。

  • 使用连接池(如 HikariCP、Druid)并配置 driver-class-name: oracle.jdbc.OracleDriver,它们通常内置驱动卸载钩子;但需确认版本(HikariCP ≥ 2.7.0 才支持)
  • 将 ojdbc.jar 移出 WEB-INF/lib,放到 Tomcat 的 lib/ 目录下,让系统类加载器统一加载——这样驱动与 WebApp 生命周期解耦,避免 WebAppClassLoader 加载它
  • 禁用 JDBC 4.0 的自动服务发现:在 WEB-INF/web.xml 中添加 <context-param><param-name>org.apache.tomcat.jdbc.pool.initSQL</param-name><param-value></param-value></context-param> 无用;真正有效的是在 META-INF/MANIFEST.MF 中为 ojdbc.jar 添加 Implementation-Title: Oracle JDBC Driver 并配合 Tomcat 的 antiJARLocking="true",但这只是辅助
  • JDK 9+ 用户注意:javax.sql.DataSource 推荐用模块化方式加载,DriverManager 已标记为 deprecated,应优先走 DataSource + JNDI 路径

真正难处理的不是怎么写 deregister 代码,而是确保它一定被执行——比如应用崩溃退出、kill -9、容器异常终止时,contextDestroyed 根本不会触发。所以生产环境必须配 -XX:MaxMetaspaceSize(JDK 8+)或 -XX:MaxPermSize(JDK 7),并监控 LoadedClassCount 指标趋势,把泄漏控制在可接受的 redeploy 次数内。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关文章

驱动精灵
驱动精灵

驱动精灵基于驱动之家十余年的专业数据积累,驱动支持度高,已经为数亿用户解决了各种电脑驱动问题、系统故障,是目前有效的驱动软件,有需要的小伙伴快来保存下载体验吧!

下载

相关标签:

oracle java

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

10497

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

7642

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

6672

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1144

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

928

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1376

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2769

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20071

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1235

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程