Last active
December 31, 2015 21:29
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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