Skip to content

Instantly share code, notes, and snippets.

@jsumners
Last active December 31, 2015 21:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsumners/8046877 to your computer and use it in GitHub Desktop.
Save jsumners/8046877 to your computer and use it in GitHub Desktop.
POS Oracle drivers refusing to unload, causing memory leaks, and killing the god damn PermGen space.
package com.jrfom.fuck.oracle;
import java.lang.management.ManagementFactory;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import oracle.jdbc.OracleDriver;
import oracle.ucp.UniversalConnectionPoolException;
import oracle.ucp.admin.UniversalConnectionPoolManager;
import oracle.ucp.admin.UniversalConnectionPoolManagerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>The Oracle driver is a piece of shit. This will keep us from leaking memory
* across re-deployments.</p>
*
* <p>Taken from http://stackoverflow.com/a/15816247</p>
* <p>With support from https://blogs.reucon.com/srt/classloader-leaks-by-oracle-9056/</p>
*/
public class OjdbcDriverListener implements ServletContextListener {
private static final Logger log = LoggerFactory.getLogger(OjdbcDriverListener.class);
private Driver driver;
@Override
public void contextInitialized(ServletContextEvent sce) {
this.driver = new OracleDriver();
boolean skipRegistration = false;
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
if (driver instanceof OracleDriver) {
OracleDriver alreadyRegistered = (OracleDriver) driver;
if (alreadyRegistered.getClass() == this.driver.getClass()) {
skipRegistration = true;
this.driver = alreadyRegistered;
break;
}
}
}
try {
if (!skipRegistration) {
DriverManager.registerDriver(this.driver);
log.info(
"Registered JDBC driver: `{} v{}.{}`",
this.driver,
this.driver.getMajorVersion(),
this.driver.getMinorVersion()
);
}
} catch (SQLException e) {
log.error("Could not register Oracle driver: `{}`", e.getMessage());
log.debug(e.toString());
throw new RuntimeException(e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (this.driver != null) {
try {
log.info("Killing the Oracle universal connection pool");
UniversalConnectionPoolManager mgr = UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager();
mgr.setJmxEnabled(false);
mgr.destroyConnectionPool("the_name_of_your_connection_pool");
log.info("Killing some bullshit MBeans");
this.killMBeans();
DriverManager.deregisterDriver(this.driver);
log.info("Deregistered JDBC driver: `{}`", this.driver);
} catch (SQLException e) {
log.error("Could not deregister driver: `{}`", e.getMessage());
log.debug(e.toString());
} catch (UniversalConnectionPoolException e) {
log.error("Could not get connection pool manager: `{}`", e.getMessage());
log.debug(e.toString());
}
this.driver = null;
} else {
log.info("No JDBC driver to deregister");
}
}
private void killMBeans() {
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
for (ObjectName mbean : mbs.queryNames(null, null)) {
final Hashtable<String, String> keys = new Hashtable<>();
final String mbeanName = mbean.getCanonicalName();
final Hashtable<String, String> properties = mbean.getKeyPropertyList();
/*log.debug("Bean => {}", mbeanName);
for (String k : properties.keySet()) {
log.debug("[{} : {}]", k, properties.get(k));
}*/
if (mbeanName.startsWith("oracle.ucp.admin") ||
mbeanName.startsWith("com.oracle.jdbc"))
{
log.debug("Killing MBean: `{}`", mbeanName);
keys.put("name", properties.get("name"));
if (properties.containsKey("type")) {
keys.put("type", properties.get("type"));
}
ObjectName objectName = new ObjectName(mbeanName.split(":")[0], keys);
mbs.unregisterMBean(objectName);
}
}
} catch (Exception e) {
log.error("Could not deregister MBean: `{}`", e.getMessage());
log.debug(e.toString());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment