Oracle leaks threads on when closing Hibernate Sessions with Oracle JDBC driver

907 views Asked by At

We are running a multi classloaders java application using Hibernate:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.4.16.Final</version>
</dependency>
<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc10-production</artifactId>
    <version>19.7.0.0</version>
    <type>pom</type>
</dependency>

We noticed that even if close all off Hibernate and artifacts and unregister the driver we still see threads left alive that hold the classloader in the contextclassloader. Is there a way to shutdown those threads Timer & OracleTimeoutPollingThread?

 public void close() throws IOException {
    sessionFactory.close();
    session.close();
    factory.close();

    try {
      Enumeration<Driver> de = DriverManager.getDrivers();
      while(de.hasMoreElements()) {
        Driver d = de.nextElement();
        if(d.getClass().getClassLoader() == RGHibernate.class.getClassLoader()) {
          DriverManager.deregisterDriver(d);
        }

      }
    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

Heap dump analysis

1

There are 1 answers

7
quaff On
    protected void cancelTimers() {
        try {
            for (Thread thread : Thread.getAllStackTraces().keySet())
                if (thread.getClass().getSimpleName().equals("TimerThread"))
                    cancelTimer(thread);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private void cancelTimer(Thread thread) throws Exception {
        // Timer::cancel
        Object queue = ReflectionUtils.getFieldValue(thread, "queue");
        Method m = queue.getClass().getDeclaredMethod("isEmpty");
        m.setAccessible(true);
        if ((boolean) m.invoke(queue)) {
            synchronized (queue) {
                ReflectionUtils.setFieldValue(thread, "newTasksMayBeScheduled", false);
                m = queue.getClass().getDeclaredMethod("clear");
                m.setAccessible(true);
                m.invoke(queue);
                queue.notify();
            }
        }
    }