【问题标题】:Loading driver jar file at runtime resulting in Perm Gen Space Error在运行时加载驱动程序 jar 文件导致 Perm Gen Space Error
【发布时间】:2014-11-17 14:52:36
【问题描述】:

我创建了一个 REST 服务,在其中我在运行时加载 JDBC 驱动程序 jar。以下是执行此操作的代码:

Driver driverInstance;
URLClassLoader driverClassLoader;
driverClassLoader = new URLClassLoader (new URL[] { "c:/mysql.jar" }, System.class.getClassLoader());
Class<?> driverClass = driverClassLoader.loadClass("oracle.jdbc.driver.OracleDriver");
Connection conn = driverInstance.connect(connectionString, userDbCredentials);

使用此连接将数据加载到数据库后,我将关闭 连接driverClassLoader 两者。但是在运行了一段时间后,我得到了 java.lang.OutOfMemoryError: PermGen space 在 tomcat 服务器中。

我获取了堆转储,并使用 eclipse Memory Analyzer 打开它,我发现以下泄漏可疑消息: “org.apache.catalina.loader.WebappClassLoader”的13个实例,由“java.net.URLClassLoader @ 0xc155fc10”加载,占用14,083,776(32.21%)字节

我知道这是由于在运行时加载了驱动程序 jar,但我无法找到解决方案。

【问题讨论】:

  • 驱动在tomcat的libs/文件夹下吗?
  • 不,它是从外部路径读取的。
  • 该代码究竟在哪里执行?类加载器的创建是每个驱动程序只创建一次,还是每次调用完成一次?
  • 代码在构造函数中执行。我都尝试了,加载一次,每次调用都加载。
  • 你知道JDBC drivers don't need to be explicitly loaded anymore吗?如果将 mysql.jar 放在 WEB-INF/lib 或 Tomcat 的库目录中,则可以将所有代码替换为一行:Connection conn = DriverManager.getConnection(connectionString, userDbCredentials);。取消显式加载驱动程序类可能会解决问题。

标签: java tomcat permgen urlclassloader


【解决方案1】:

当您加载 JDBC 驱动程序类时,它会将自己注册到 java.sql.DriverManager。即使您尝试使系统类加载器成为您的URLClassLoader 的父级,我相信它也会从您的WebappClassLoader 继承AccessControlContext,从而引用它。使用 Eclipse Memory Analyzer (MAT) 分析引用可以帮助验证 - see this blog post for instructions

假设 JDBC 驱动程序实际上是泄漏的源头,那么解决问题的方法是调用 java.sql.DriverManager.deregisterDriver() 以显式取消注册驱动程序,最好在 ServletContextListenercontextDestroyed() 中。

通常您可以让我的ClassLoader leak prevention library 为您取消注册,但是由于驱动程序是在单独的类加载器中加载的,因此无法开箱即用。但是,您可以进行一些子类化/修改。好处是您可以免费获得更多的泄漏保护。

您是否真的想要并且需要在运行时从应用程序外部加载驱动程序 - 嗯,这是一个单独的问题...

祝你好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-15
    • 2011-08-06
    • 2014-11-26
    • 1970-01-01
    • 2017-03-09
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    相关资源
    最近更新 更多