ã·ã¹ãã ã©ã€ãã©ãªã®ããŠã³ããŒãã¯éåžžã«ç°¡åã§ãããçµæãšããŠã¢ã³ããŒãããã«ã¯ãå€ãã®åªåãå¿ èŠã§ãã ã·ã¹ãã ã©ã€ãã©ãªãã©ã®ãããæ£ç¢ºã«ã¢ã³ããŒãããããªããããå¿ èŠãªã®ããæããŠã¿ãŸãã
ãŠãŒã¶ãŒãããŒã«ã«ãããã¯ãŒã¯äžã®ã³ã³ãã¥ãŒã¿ãŒã§å®è¡ããå°ããªãŠãŒãã£ãªãã£ãäœæãããšããŸãã ããã°ã©ã ã®ã€ã³ã¹ããŒã«ãšæ§æã«é¢ããåé¡ãããŠãŒã¶ãŒãæãããã®ã§ãããéäžåã€ã³ãã©ã¹ãã©ã¯ãã£ãå±éããŠç¶æããããã®ãªãœãŒã¹ã¯ãããŸããã ãã®ãããªå Žåãéåžžããã¹ãŠã®äŸåé¢ä¿ãšãšãã«ããã°ã©ã ã1ã€ã®jarãã¡ã€ã«ã«ã¢ã»ã³ãã«ããŸãã ããã¯ãmaven-assembly-pluginã䜿çšããããIDE Runnable jarãããšã¯ã¹ããŒãããã ãã§ç°¡åã§ãã æ¬¡ã®ã³ãã³ãã§ããã°ã©ã ãèµ·åããŸãã
java -jar my-program.jar
æ®å¿µãªãããã©ã€ãã©ãªã®1ã€ããã®åäœã«ã·ã¹ãã åçã©ã€ãã©ãªãã€ãŸãdllãå¿ èŠãšããå Žåãããã¯æ©èœããŸããã éåžžããã®ãããªã©ã€ãã©ãªã®ã¯ã©ã¹ã®1ã€ã§ã¯ãéçåæååã§System.loadLibraryïŒïŒã®åŒã³åºããè¡ãããŸãã dllãããŒãããã«ã¯ãJVMã·ã¹ãã ããããã£java.library.pathããã¢ã¯ã»ã¹ã§ãããã£ã¬ã¯ããªã«é 眮ããå¿ èŠããããŸãã ãã®åé¿çã¯ã©ã®ããã«åé¿ã§ããŸããïŒ
jarãã¡ã€ã«å ã«dllãããã¯ããŸãã dllã®ããŒããå¿ èŠãšããã¯ã©ã¹ã®äœ¿çšãéå§ããåã«ãäžæãã£ã¬ã¯ããªãäœæããããã«ã©ã€ãã©ãªãæœåºããŠããã£ã¬ã¯ããªãjava.library.pathã«è¿œå ããŸãã æ¬¡ã®ããã«ãªããŸãã
prepareLibrary
private void addLibraryPath(String pathToAdd) throws ReflectiveOperationException { Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths"); usrPathsField.setAccessible(true); String[] paths = (String[]) usrPathsField.get(null); String[] newPaths = Arrays.copyOf(paths, paths.length + 1); newPaths[newPaths.length - 1] = pathToAdd; usrPathsField.set(null, newPaths); } private Path prepareLibrary() throws IOException, ReflectiveOperationException { Path dir = Files.createTempDirectory("lib"); try (InputStream input = ExampleClass.class.getResourceAsStream("custom.dll")) { if (input == null) { throw new FileNotFoundException("Can't load resource custom.dll"); } Files.copy(input, dir.resolve("custom.dll")); } addLibraryPath(dir.toAbsolutePath().toString()); return dir; }
æ®å¿µãªãããJava 㯠java.library.pathãæ¡åŒµããæšæºã¡ãœãããæäŸããŠããªãããããªãã¬ã¯ã·ã§ã³ã§ååŠåããå¿ èŠããããŸãã
ã©ã€ãã©ãªã®ããŒãã¯ãŠãŒã¶ãŒã«ãšã£ãŠééçã§ããããã¡ã€ã«ã®ã³ããŒãç°å¢å€æ°ã®èšå®ã«ã€ããŠå¿é ããå¿ èŠã¯ãããŸããã åäœããã«ã¯ãéåžžã®ã¹ã¯ãªãããå®è¡ããã ãã§ååã§ãã ãã ããããã°ã©ã ãéå§ãããã³ã«ããã¡ã€ã«ã®ããäžæãã£ã¬ã¯ããªãæ®ããŸãã ããã¯ããŸãè¯ããªãã®ã§ãåºåããããã«ããªããã°ãªããŸããã
try { ... } finally { delete(dir); }
ããããWindowsã§ã¯ããã¯æ©èœããŸããã JVMã«ããŒããããã©ã€ãã©ãªã¯ãdllãã¡ã€ã«ãšãããååšãããã£ã¬ã¯ããªãããã¯ããŸãã ãããã£ãŠãããã°ã©ã ãæ£ç¢ºã«çµäºããåé¡ã解決ããã«ã¯ãJVMããã·ã¹ãã åçã©ã€ãã©ãªãã¢ã³ããŒãããå¿ èŠããããŸãã
解決ããã
ãŸããã³ãŒãã«èšºæã远å ããã®ã劥åœã§ãã ããšãã°ããã¡ã€ã«ãåé€ãããå Žåã ã©ã€ãã©ãªã䜿çšãããªãã£ãå Žåãäœãããå¿ èŠã¯ãããŸããããã¡ã€ã«ãããã¯ãããŠããå Žåã¯ã远å ã®å¯Ÿçãè¬ããŠãã ããã
if (!delete(dir)) { forceDelete(dir); }
è¿ éã§ã¯ãããæãçŸãããœãªã¥ãŒã·ã§ã³ã§ã¯ãªããããã¹ã±ãžã¥ãŒã©ã䜿çšããŸããã åºåã§ã1ååŸã«cmd / c rd / s / q temp-dirã³ãã³ããå®è¡ããã¿ã¹ã¯ãå«ãxmlãã¡ã€ã«ãäœæããschtasks -create taskName -xml taskFile.xmlã³ãã³ãã䜿çšããŠã¿ã¹ã¯ãã¹ã±ãžã¥ãŒã©ã«ããŒãããŸãã ã¿ã¹ã¯ãå®äºãããŸã§ã«ãããã°ã©ã ã¯æ¢ã«å®äºããŠããããã¡ã€ã«ãä¿æããŠãããŠãŒã¶ãŒã¯ããŸããã
æãæ£ããæ±ºå®ã¯ãJavaãã·ã³ã䜿çšããŠã©ã€ãã©ãªãŒãã¢ã³ããŒãããããšã§ãã ããã¥ã¡ã³ãã«ã¯ãã¯ã©ã¹ãåé€ããããšã·ã¹ãã ã©ã€ãã©ãªãã¢ã³ããŒããããã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã1ã€ãæ®ã£ãŠããªãå Žåãã¯ã©ã¹ããŒããŒãšãšãã«ã¯ã©ã¹ãã¬ããŒãžã³ã¬ã¯ã¿ãŒã«ãã£ãŠåé€ããããšæžãããŠããŸãã ç§ã®æèŠã§ã¯ããã¹ãŠã®ã¡ã¢ãªãšä»ã®ãªãœãŒã¹ãå®å šã«ã¯ãªãŒã³ã¢ãããããããªã³ãŒããåžžã«èšè¿°ããæ¹ãè¯ããšæããŸãã ã³ãŒããäœã圹ã«ç«ã€å Žåã¯ãé ããæ©ããã³ãŒããåå©çšããŠãä»ã®ã³ã³ããŒãã³ããã€ã³ã¹ããŒã«ãããŠãããµãŒããŒã«ãããã€ããå¿ èŠãããããã§ãã ããã§ãããã°ã©ã ã䜿çšããŠdllãæ£ããã¢ã³ããŒãããæ¹æ³ãèŠã€ããããã«æéããããããšã«ããŸããã
ã¯ã©ã¹ããŒããŒã䜿çšãã
ç§ã®ããã°ã©ã ã§ã¯ãåé¡ã¯JDBCãã©ã€ããŒã«èµ·å ããŠãããããJDBCã®äŸãåŒãç¶ãèŠãŠãããŸãã ãã ããåæ§ã®æ¹æ³ã§ä»ã®ã©ã€ãã©ãªãæäœã§ããŸãã
dllãã·ã¹ãã ã¯ã©ã¹ããŒããŒããããŒãããããšãã¢ã³ããŒãã§ããªããªããŸãããã®ãããã©ã€ãã©ãªããã«ããã¯ã©ã¹ãããŒããããããã«ã¯ã©ã¹ããŒããŒãäœæããå¿ èŠããããŸãã æ°ããã¯ã©ã¹ããŒããŒã¯ã芪ããããã£ãä»ããŠã·ã¹ãã ã¯ã©ã¹ããŒããŒã«æ¥ç¶ããå¿ èŠããããŸããããããªããšãæååããªããžã§ã¯ããããã³ãšã³ãããŒã«å¿ èŠãªãã®ä»ã®ãã®ã䜿çšã§ããªããªããŸãã
詊ããŠã¿ãŸãããïŒ
æ°ããããŒãããŒããŒããã¯ã©ã¹ãããŒãããïŒ1ïŒ
ClassLoader parentCl = ExampleClass.class.getClassLoader(); classLoader = new URLClassLoader(new URL[0], parentCl); Class.forName("org.jdbc.CustomDriver", classLoader, true); try (Connection connection = DriverManager.getConnection(dbUrl, dbProperties)) { if (connection.getClass().getClassLoader() != classLoader) { System.out.printf("- %n"); } ... }
åäœããŸããã ã¯ã©ã¹ãããŒããããšããæåã«èŠªããŒããŒããã¯ã©ã¹ãæã¡äžããããšããããããã©ã€ããŒã¯å¿ èŠã«å¿ããŠããŒãããŸããã§ããã æ°ããã¯ã©ã¹ããŒããŒã䜿çšããã«ã¯ãããã°ã©ã jarãã¡ã€ã«ããJDBCãã©ã€ããŒãåé€ããŠãã·ã¹ãã ããŒããŒããã¢ã¯ã»ã¹ã§ããªãããã«ããå¿ èŠããããŸãã ãã®ãããã©ã€ãã©ãªãåã蟌ã¿jarãã¡ã€ã«ã®åœ¢åŒã§ããã¯ãã䜿çšããåã«äžæãã£ã¬ã¯ããªïŒdllãååšããå Žæãšåãå ŽæïŒã«å±éããŸãã
æ°ããããŒãããŒããŒããã®ã¯ã©ã¹ã®èªã¿èŸŒã¿ïŒ2ïŒ
ClassLoader cl = ExampleClass.class.getClassLoader(); URL url = UnloadableDriver.class.getResource("CustomJDBCDriver.jar"); if (url == null) { throw new FileNotFoundException("Can't load resource CustomJDBCDriver.jar"); } Path dir = prepareLibrary(); try (InputStream stream = url.openStream()) { Path target = dir.resolve("CustromJDBCDriver.jar"); Files.copy(stream, target); url = target.toUri().toURL(); } ClassLoader classLoader = new URLClassLoader(new URL[] {url}, cl); Class.forName("org.jdbc.CustomDriver", true, classLoader); try (Connection connection = DriverManager.getConnection(dbUrl, dbProperties)) { if (connection.getClass().getClassLoader() != classLoader) { System.out.printf("- %n"); } else { System.out.printf(", %n"); } ... }
æ°ããããŒãããŒããŒãããªããžã§ã¯ããããŒãããŸãããäœæ¥ã®æåŸã«ãéãããã¹ãŠã®ãã®ãéãããã¹ãŠã®å€æ°ãã¯ãªãŒã³ã¢ããããæããã«System.gcïŒïŒãåŒã³åºããŸãããã®åŸããã¡ã€ã«ã®ã¯ãªãŒã³ã¢ããã詊ã¿ãŸãã ãã®æç¹ã§ãæç€ºçãªåæåã¡ãœããã䜿çšããŠãã¯ã©ã¹ããŒããŒãæäœããããžãã¯å šäœãå¥ã®ã¯ã©ã¹ã«ã«ãã»ã«åããããšã¯çã«ããªã£ãŠããŸãã
ã¡ã€ã³ã¯ã©ã¹ã®ã¹ã±ã«ãã³
public class ExampleClass implements AutoCloseable { private final Path dir; private URLClassLoader classLoader; public ExampleClass() { ... } public void doWork() { ... } @Override public void close() { ... this.classLoader.close(); this.classloader = null; System.gc(); // - dll if (!delete(this.dir)) { scheduleRemovalToTaskschd(this.dir); } } } public class Main { public static void main(String args[]) { try (ExampleClass example = new ExampleClass()) { example.doWork(); } catch (Throwable e) { e.printStackTrace(); } } }
ã¬ããŒãžã³ã¬ã¯ã¿ãŒã®å®éš
ã©ã€ãã©ãªã®ã¢ã³ããŒãã«ã¯ãã¹ãŠãæ£åŒã«å¿ èŠãšæããããšããäºå®ã«ãããããããå®éã«ã¯ã¢ã³ããŒãã¯è¡ãããŸããã java.langããã±ãŒãžãããœãŒã¹ãèªã¿åãããšã§ããã€ãã£ãã©ã€ãã©ãªã®åé€ããå éšã¯ã©ã¹ã®ããããã®finalizeïŒïŒã¡ãœããã§è¡ãããŠããããšã確èªã§ããŸããã ããã¥ã¡ã³ãã«ã¯ããã®ã¡ãœããããã€å®è¡ãããã®ãããŸã£ããå®è¡ãããã®ãã«ã€ããŠã®æ£ç¢ºãªå®çŸ©ã瀺ãããŠããªããããããã¯èŠçã§ãããé©ãã¹ãããšã§ãã ã€ãŸããæåã¯ãããŸããŸãªç°å¢ãããŸããŸãªããŒãžã§ã³ã®JVMããŸãã¯ããŸããŸãªã¬ããŒãžã³ã¬ã¯ã¿ãŒã§ç°ãªãå¯èœæ§ã®ããããã€ãã®èŠå ã«äŸåããŸãã ãã ããåžæãäžããSystem.runFinalizationïŒïŒã¡ãœããããããŸãã
ç§éã¯è©Šã¿ãŸãïŒ
ãã¡ã€ãã©ã€ãºãå®è¡...
@Override public void close() { ... this.classLoader.close(); this.classloader = null; System.gc(); System.runFinalization(); // - dll if (!delete(this.dir)) { scheduleRemovalToTaskschd(this.dir); } }
åäœããŸããã ãã£ã¬ã¯ããªã¯Javaããã»ã¹ã«ãã£ãŠããã¯ãããŠããŸãã ãããããã®ãã¯ããã¯ã䜿çšããŸããã
- System.in.readïŒïŒãåºåã«é 眮ããŸãã
- ããã°ã©ã ããã®å Žæã§åæ¢ãããšãjvisualvmããã¡ã¢ãªãã³ããäœæããŸã
- Eclipse Memory Analysis ToolãŸãã¯jhatã䜿çšããŠãã³ããç£èŠãã
- ã¯ã©ã¹ãããŒããŒã«ãã£ãŠããŒãããããªããžã§ã¯ãã®ã€ã³ã¹ã¿ã³ã¹ãæ¢ããŠããŸã
æŒãã®åå ã¯5ã€ãããŸããã
- ããŒã«ã«å€æ°
- ãã©ã€ããŒãããŒãžã£ãŒ
- ãªãœãŒã¹ãã³ãã«
- ã¹ã¬ããããŒã«ã«
- äŸå€
ããŒã«ã«å€æ°
ã¬ããŒãžã³ã¬ã¯ã¿ãŒã¯ã倿°ãã¹ã³ãŒãå€ã«ãªã£ãå Žåã§ãããã®å€æ°ãå«ã颿°ãå®äºãããŸã§ãããŒã«ã«å€æ°ãå°éäžèœã§ãããšã¯èŠãªããªãããšã倿ããŸããã
ãããã£ãŠãã¯ã©ã¹ããŒããŒã®ã¢ã³ããŒãã®åé¡ã解決ããã«ã¯ãgcãåŒã³åºãåã«ãã¢ã³ããŒããããã¯ã©ã¹ã䜿çšãããã¹ãŠã®é¢æ°ãçµäºããå¿ èŠããããŸãã
ããŒã«ã«å€æ°
ã¬ããŒãžã³ã¬ã¯ã¿ãŒã¯ã倿°ãã¹ã³ãŒãå€ã«ãªã£ãå Žåã§ãããã®å€æ°ãå«ã颿°ãå®äºãããŸã§ãããŒã«ã«å€æ°ãå°éäžèœã§ãããšã¯èŠãªããªãããšã倿ããŸããã
if (needConnection) { try (Connection connection = DriverManager.connect()) { ... } } // connection .
ãããã£ãŠãã¯ã©ã¹ããŒããŒã®ã¢ã³ããŒãã®åé¡ã解決ããã«ã¯ãgcãåŒã³åºãåã«ãã¢ã³ããŒããããã¯ã©ã¹ã䜿çšãããã¹ãŠã®é¢æ°ãçµäºããå¿ èŠããããŸãã
ãã©ã€ããŒãããŒãžã£ãŒ
ã¯ã©ã¹ãããŒããããšãJDBCãã©ã€ããŒã¯registerDriverïŒïŒã¡ãœããã«ãã£ãŠDriverManagerã¯ã©ã¹ã«ç»é²ãããŸãã ã©ããããã¢ã³ããŒãããåã«ãderegisterDriverïŒïŒã¡ãœãããåŒã³åºãå¿ èŠããããŸãã ãã£ãŠã¿ãŸãã
åäœããŸããã Heapdumpã¯å€æŽãããŠããŸããã DriverManagerã¯ã©ã¹ã®ãœãŒã¹ã³ãŒãã確èªãããšãderegisterDriverïŒïŒã¡ãœããã¯ãregisterDriverïŒïŒãåŒã³åºããã¯ã©ã¹ãšåãã¯ã©ã¹ããŒããŒã«å±ããã¯ã©ã¹ããã®åŒã³åºãã§ãªããã°ãªããªãããšã確èªããŸãã ãããŠregisterDriverïŒïŒã¯ãéçåæååãããã©ã€ããŒèªäœã«ãã£ãŠåŒã³åºãããŸãã äºæ³å€ã®ã¿ãŒã³ã
ãã©ã€ããŒãçŽæ¥ç»é²è§£é€ã§ããªãããšãããããŸããã 代ããã«ãæ°ããã¯ã©ã¹ããŒããŒã®ã¯ã©ã¹ã«èªåã®ä»£ããã«å®è¡ããããäŸé Œããå¿ èŠããããŸãã æ¹æ³ã¯ãç¹å¥ãªDriverManagerProxyã¯ã©ã¹ãããã«æ£ç¢ºã«ã¯2ã€ã®ã¯ã©ã¹ãšã€ã³ã¿ãŒãã§ãŒã¹ãäœæããããšã§ãã
ã€ã³ã¿ãŒãã§ãŒã¹ã¯ã¡ã€ã³ã®ã¯ã©ã¹ãã¹ã«ãããå®è£ ã¯JDBCãã©ã€ããŒãšãšãã«è£å©jarãã¡ã€ã«ããæ°ããããŒããŒã«ãã£ãŠããŒããããŸãã çè«çã«ã¯ãã€ã³ã¿ãŒãã§ã€ã¹ãçãããšãã§ããŸããã颿°ãåŒã³åºãã«ã¯ãªãã¬ã¯ã·ã§ã³ã䜿çšããå¿ èŠããããŸãã ãããã·ã¯æ¬¡ã®ããã«äœ¿çšãããŸãã
ãã©ã€ããŒãããŒãžã£ãŒ
ã¯ã©ã¹ãããŒããããšãJDBCãã©ã€ããŒã¯registerDriverïŒïŒã¡ãœããã«ãã£ãŠDriverManagerã¯ã©ã¹ã«ç»é²ãããŸãã ã©ããããã¢ã³ããŒãããåã«ãderegisterDriverïŒïŒã¡ãœãããåŒã³åºãå¿ èŠããããŸãã ãã£ãŠã¿ãŸãã
Enumeration<Driver> drivers = driverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); if (driver.getClass().getClassLoader() == classLoader) { DriverManager.deregisterDriver(driver); break; } }
åäœããŸããã Heapdumpã¯å€æŽãããŠããŸããã DriverManagerã¯ã©ã¹ã®ãœãŒã¹ã³ãŒãã確èªãããšãderegisterDriverïŒïŒã¡ãœããã¯ãregisterDriverïŒïŒãåŒã³åºããã¯ã©ã¹ãšåãã¯ã©ã¹ããŒããŒã«å±ããã¯ã©ã¹ããã®åŒã³åºãã§ãªããã°ãªããªãããšã確èªããŸãã ãããŠregisterDriverïŒïŒã¯ãéçåæååãããã©ã€ããŒèªäœã«ãã£ãŠåŒã³åºãããŸãã äºæ³å€ã®ã¿ãŒã³ã
ãã©ã€ããŒãçŽæ¥ç»é²è§£é€ã§ããªãããšãããããŸããã 代ããã«ãæ°ããã¯ã©ã¹ããŒããŒã®ã¯ã©ã¹ã«èªåã®ä»£ããã«å®è¡ããããäŸé Œããå¿ èŠããããŸãã æ¹æ³ã¯ãç¹å¥ãªDriverManagerProxyã¯ã©ã¹ãããã«æ£ç¢ºã«ã¯2ã€ã®ã¯ã©ã¹ãšã€ã³ã¿ãŒãã§ãŒã¹ãäœæããããšã§ãã
public interface DriverManagerProxy { void deregisterDriver(Driver driver) throws SQLException; } public class DriverManagerProxyImpl implements DriverManagerProxy { @Override public void deregisterDriver(Driver driver) throws SQLException { DriverManager.deregisterDriver(driver); } }
ã€ã³ã¿ãŒãã§ãŒã¹ã¯ã¡ã€ã³ã®ã¯ã©ã¹ãã¹ã«ãããå®è£ ã¯JDBCãã©ã€ããŒãšãšãã«è£å©jarãã¡ã€ã«ããæ°ããããŒããŒã«ãã£ãŠããŒããããŸãã çè«çã«ã¯ãã€ã³ã¿ãŒãã§ã€ã¹ãçãããšãã§ããŸããã颿°ãåŒã³åºãã«ã¯ãªãã¬ã¯ã·ã§ã³ã䜿çšããå¿ èŠããããŸãã ãããã·ã¯æ¬¡ã®ããã«äœ¿çšãããŸãã
DriverManagerProxyã䜿çšãã
public class ExampleClass implements AutoCloseable { private final Path dir; private URLClassLoader classLoader; private DriverManagerProxy driverManager; public ExampleClass() { ... this.classLoader = ...; Class.forName("org.jdbc.CustomDriver", true, classLoader); Class<?> dmClass = Class.forName("ru.example.DriverManagerProxyImpl", true, classLoader); this.driverManager = (DriverManagerProxy) dmClass.newInstance(); } public void doWork() { ... } @Override public void close() { ... Enumeration<Driver> drivers = driverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); if (driver.getClass().getClassLoader() == classLoader) { driverManager.deregisterDriver(driver); break; } } this.driverManager = null; this.classLoader.close(); this.classloader = null; System.gc(); System.runFinalization(); // - dll if (!delete(this.dir)) { scheduleRemovalToTaskschd(this.dir); } } }
ãªãœãŒã¹ãã³ãã«
ç§ãã¢ã³ããŒãããããšããæ¬¡ã®ã¯ã©ã¹ããŒããŒã®æãããã¯ãResourceBundleã¯ã©ã¹ã®è žã§èŠã€ãããŸããã ãããããDriverManagerãšã¯ç°ãªããResourceBundleã«ã¯ç¹å¥ãªé¢æ°clearCacheïŒïŒãçšæãããŠãããã¯ã©ã¹ããŒããŒããã©ã¡ãŒã¿ãŒãšããŠæž¡ãããŸãã
ãœãŒã¹ã«ãã£ãŠå€æãããšãResourceBundleã¯ã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã«å¹²æžããŠã¯ãªããªã匱ããªã³ã¯ã䜿çšããããšã«æ³šæããŠãã ããã ããããããªããžã§ã¯ããžã®ä»ã®ãã¹ãŠã®ãªã³ã¯ãã¯ãªã¢ããå Žåããã®ãã£ãã·ã¥ãã¯ãªã¢ããå¿ èŠã¯ãããŸããã
ãªãœãŒã¹ãã³ãã«
ç§ãã¢ã³ããŒãããããšããæ¬¡ã®ã¯ã©ã¹ããŒããŒã®æãããã¯ãResourceBundleã¯ã©ã¹ã®è žã§èŠã€ãããŸããã ãããããDriverManagerãšã¯ç°ãªããResourceBundleã«ã¯ç¹å¥ãªé¢æ°clearCacheïŒïŒãçšæãããŠãããã¯ã©ã¹ããŒããŒããã©ã¡ãŒã¿ãŒãšããŠæž¡ãããŸãã
ResourceBundle.clearCache(classLoader);
ãœãŒã¹ã«ãã£ãŠå€æãããšãResourceBundleã¯ã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã«å¹²æžããŠã¯ãªããªã匱ããªã³ã¯ã䜿çšããããšã«æ³šæããŠãã ããã ããããããªããžã§ã¯ããžã®ä»ã®ãã¹ãŠã®ãªã³ã¯ãã¯ãªã¢ããå Žåããã®ãã£ãã·ã¥ãã¯ãªã¢ããå¿ èŠã¯ãããŸããã
ã¹ã¬ããããŒã«ã«
æªäœ¿çšã®ãã©ã€ããŒã®æ«å°ŸãæåŸã«çŸããã®ã¯ãThreadLocalsã§ããã DriverManagerã®è©±ã®åŸãããŒã«ã«ã¹ã¬ãã倿°ãã¯ãªã¢ããããšã¯ãããã€ãã®äºçްãªããšã®ããã«æããŸãã åçããã«ã¯ã§ããŸããã§ãããã
ã¹ã¬ããããŒã«ã«
æªäœ¿çšã®ãã©ã€ããŒã®æ«å°ŸãæåŸã«çŸããã®ã¯ãThreadLocalsã§ããã DriverManagerã®è©±ã®åŸãããŒã«ã«ã¹ã¬ãã倿°ãã¯ãªã¢ããããšã¯ãããã€ãã®äºçްãªããšã®ããã«æããŸãã åçããã«ã¯ã§ããŸããã§ãããã
private static void cleanupThreadLocals(ClassLoader cl) throws ReflectiveOperationException { int length = 1; Thread threads[] = new Thread[length]; int cnt = Thread.enumerate(threads); while (cnt >= length) { length *= 2; threads = new Thread[length]; cnt = Thread.enumerate(threads); } for (int i = 0; i < cnt; i++) { Thread thread = threads[i]; if (thread == null) { continue; } cleanupThreadLocals(thread, cl); } } private static void cleanupThreadLocals(Thread thread, ClassLoader cl) throws ReflectiveOperationException { Field threadLocalsField = Thread.class.getDeclaredField("threadLocals"); threadLocalsField.setAccessible(true); Object threadLocals = threadLocalsField.get(thread); if (threadLocals == null) { return; } Class<?> threadLocalsClass = threadLocals.getClass(); Field tableField = threadLocalsClass.getDeclaredField("table"); tableField.setAccessible(true); Object table = tableField.get(threadLocals); Object entries[] = (Object[]) table; Class<?> entryClass = table.getClass().getComponentType(); Field valueField = entryClass.getDeclaredField("value"); valueField.setAccessible(true); Method expungeStaleEntry = threadLocalsClass.getDeclaredMethod("expungeStaleEntry", Integer.TYPE); expungeStaleEntry.setAccessible(true); for (int i = 0; i < entries.length; i++) { Object entry = entries[i]; if (entry == null) { continue; } Object value = valueField.get(entry); if (value != null) { ClassLoader valueClassLoader = value.getClass().getClassLoader(); if (valueClassLoader == cl) { ((java.lang.ref.Reference<?>) entry).clear(); expungeStaleEntry.invoke(threadLocals, i); } } } }
äŸå€
ã¯ãªãŒã³ã¢ããã³ãŒããfinallyãããã¯ã«é 眮ã§ããããšãé¡ã£ãŠããŸãã ãã®ãããã¯ã®å ¥ãå£ã§ãtry-with-resourcesã¡ã«ããºã ã䜿çšããŠãã¹ãŠãèªåçã«éããå¿ èŠããããŸãã ãã ãããã®ã¯ã©ã¹ããŒããŒã«ãã£ãŠã¯ã©ã¹ãããŒããããtryãããã¯ããäŸå€ãã¹ããŒãããå Žåãã¯ã©ã¹ããŒããŒã¯ãã®ã¡ã¢ãªããåé€ãããŸããã
ã¡ã¢ãªããäžèŠãªäŸå€ãåé€ããã«ã¯ããã£ããããŠåŠçããå¿ èŠããããŸãããšã©ãŒãã¹ããŒããå¿ èŠãããå Žåã¯ãäŸå€ãå¥ã®ã¯ã©ã¹ã«ã³ããŒããŸãã ãããç§ã®ããã°ã©ã ã§ã®ããæ¹ã§ãïŒ
äŸå€
ã¯ãªãŒã³ã¢ããã³ãŒããfinallyãããã¯ã«é 眮ã§ããããšãé¡ã£ãŠããŸãã ãã®ãããã¯ã®å ¥ãå£ã§ãtry-with-resourcesã¡ã«ããºã ã䜿çšããŠãã¹ãŠãèªåçã«éããå¿ èŠããããŸãã ãã ãããã®ã¯ã©ã¹ããŒããŒã«ãã£ãŠã¯ã©ã¹ãããŒããããtryãããã¯ããäŸå€ãã¹ããŒãããå Žåãã¯ã©ã¹ããŒããŒã¯ãã®ã¡ã¢ãªããåé€ãããŸããã
ã¡ã¢ãªããäžèŠãªäŸå€ãåé€ããã«ã¯ããã£ããããŠåŠçããå¿ èŠããããŸãããšã©ãŒãã¹ããŒããå¿ èŠãããå Žåã¯ãäŸå€ãå¥ã®ã¯ã©ã¹ã«ã³ããŒããŸãã ãããç§ã®ããã°ã©ã ã§ã®ããæ¹ã§ãïŒ
try { ... } catch (RuntimeException e) { if (e.getClass().getClassLoader() == this.getClass().getClassLoader()) { throw e; } RuntimeException exception = new RuntimeException(String.format("%s: %s", e.getClass(), e.getMessage())); exception.setStackTrace(e.getStackTrace()); throw exception; } catch (SQLException e) { if (e.getClass().getClassLoader() == this.getClass().getClassLoader()) { throw e; } SQLException exception = new SQLException(String.format("%s: %s", e.getClass(), e.getMessage())); exception.setStackTrace(e.getStackTrace()); throw exception; }
Javaã®åæ
ããŒãžåãããã¯ã©ã¹ãžã®æ€åºããããã¹ãŠã®åç §ãã¯ãªã¢ããåŸãå°ãççŸããç¶æ³ã倿ããŸããã ã¡ã¢ãªãã³ããã倿ãããšãã¡ã¢ãªå ã«ãªããžã§ã¯ãã¯ãããŸããããã¹ãŠã®ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹æ°ã¯0ã§ããããããã¯ã©ã¹èªäœãšãã®ããŒããŒã¯æ¶ããããã€ãã£ãã©ã€ãã©ãªã¯ããã«å¿ããŠåé€ãããŸããã§ããã
ãã®ææ³ã§åé¡ã解決ããããšã倿ããŸããã
System.gc(); System.runFinalization(); System.gc(); System.runFinalization();
ãããããç§ã䜿çšããJava 1.7ã§ã¯ãPermGenã«ãããªããžã§ã¯ããã¯ãªãŒãã³ã°ãããšããç¹æ®æ§ããããŸããã ã¢ããªã±ãŒã·ã§ã³ãµãŒããŒãå«ãããŸããŸãªç°å¢ã§åçã«åäœããã³ãŒããèšè¿°ããããšãããããã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã®èšå®ã詊ããŸããã§ããã
æå®ãããåä¿¡åŸãã³ãŒãã¯é©åã«æ©èœããã©ã€ãã©ãªãã¢ã³ããŒãããããã£ã¬ã¯ããªãåé€ãããŸããã ãã ããJava 8ã«åãæ¿ããåŸãåé¡ãè¿ãããŸããã åé¡ãäœã§ããããçè§£ããæéã¯ãããŸããã§ããããæããã«ãã¬ããŒãžã³ã¬ã¯ã¿ãŒã®åäœã«äœãã倿ŽãããŸããã
ãããã£ãŠãéç ²ãã€ãŸãJMXã䜿çšããå¿ èŠããããŸããã
Javaã§ãŽããåéããæ¹æ³
private static void dumpHeap() { try { Class<?> clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean"); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); Object hotspotMBean = ManagementFactory.newPlatformMXBeanProxy( server, "com.sun.management:type=HotSpotDiagnostic", clazz); Method m = clazz.getMethod("dumpHeap", String.class, boolean.class); m.invoke(hotspotMBean, "nul", true); } catch (@SuppressWarnings("unused") RuntimeException e) { return; } catch (@SuppressWarnings("unused") ReflectiveOperationException e) { return; } catch (@SuppressWarnings("unused") IOException e) { return; } }
HotSpotDiagnosticMXBeanãä»ããŠãã¹ãã¬ãŒãžãã³ããåŒã³åºããŸãã ãã¡ã€ã«åãšããŠnulãæå®ããŸããããã¯ãWindowsã§ã¯Unixã®/ dev / nullãšåãããšãæå³ããŸãã 2çªç®ã®ãã©ã¡ãŒã¿ãŒã¯ãã©ã€ããªããžã§ã¯ãã®ã¿ããã³ãã«ã¢ã³ããŒãããå¿ èŠãããããšã瀺ããŸãã JVMããã«ã¬ããŒãžã³ã¬ã¯ã·ã§ã³ãå®äºããã®ã¯ããã®ãã©ã¡ãŒã¿ãŒã§ãã
ãã®ã©ã€ãããã¯ã®åŸãäžæãã£ã¬ã¯ããªããã©ã€ãã©ãªãåé€ããåé¡ã¯çºçããªããªããŸããã æçµçãªãã¡ã€ã«ã¯ãªãŒã³ã¢ããã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
this.classLoader = null; System.gc(); System.runFinalization(); System.gc(); System.runFinalization(); if (!delete(this.dir)) { dumpHeap(); if (!delete(this.dir)) { scheduleRemovalToTaskschd(this.dir); } }
OSGIã«ããæ€èšŒ
ã³ãŒãã®å質ã確èªããããã«ãJDBCãã©ã€ããŒãäœæããŸãããããã«ãããå®å šã«ã¯ãªãŒã³ã¢ãããããŸãã å¥ã®ã¯ã©ã¹ãã¹ããããŒããããä»ã®ãã©ã€ããŒã®ã©ãããŒã®ããã«æ©èœããŸãã
UnloadableDriver
public class UnloadableDriver implements Driver, AutoCloseable { private final Path dir; // , private URLClassLoader classLoader; private DriverManagerProxy driverManager; private Driver driver; public UnloadableDriver() throws SQLException { ... } @Override public void close() { ... } ... }
ãã®ãã©ã€ããŒãApache Felixã®OSGIãµãŒãã¹ã«æ¿å ¥ããŸããã
JDBCService
public interface JDBCService { Connection getConnection(String url, Properties properties) throws SQLException; } @Service(JDBCService.class) public class JDBCServiceImpl implements JDBCService { private UnloadableDriver driver; @Activate public void activate(ComponentContext ctx) throws SQLException { this.driver = new UnloadableDriver(); } @Deactivate public void deactivate() { this.driver.close(); this.driver = null; } @Override public Connection getConnection(String url, Properties info) throws SQLException { return this.driver.connect(url, properties); } }
Java 1.8.0_102ã§å®è¡ãããŠããApache Felixã·ã¹ãã ã³ã³ãœãŒã«ããã¢ãžã¥ãŒã«ãèµ·åãããšãdllãã¡ã€ã«ãå«ãäžæãã£ã¬ã¯ããªã衚瀺ãããŸãã Javaããã»ã¹ã«ãã£ãŠããã¯ããããã¡ã€ã«ã ã¢ãžã¥ãŒã«ã忢ãããšããã«ããã£ã¬ã¯ããªã¯èªåçã«åé€ãããŸãã UnloadableDriverã䜿çšãã代ããã«ãDriverManagerãšEmbedded-Artifactsã®éåžžã®ã©ã€ãã©ãªã䜿çšããå Žåãã¢ãžã¥ãŒã«ã®æŽæ°åŸããšã©ãŒjava.lang.UnsatisfiedLinkErrorïŒNative Libraryã¯ãã§ã«å¥ã®ã¯ã©ã¹ããŒããŒã«ããŒããããŠããŸãã
çµè«
ã·ã¹ãã ãã€ãããã¯ã©ã€ãã©ãªãJavaãã·ã³ããã¢ã³ããŒãããæ®éçãªæ¹æ³ã¯ãããŸãããããã®åé¡ã¯è§£æ±ºãããŠããŸãã
Javaã«ã¯ã¯ã©ã¹ãžã®åç §ã誀ã£ãŠæ®ãããšãã§ããå€ãã®å Žæããããããã¯ã¡ã¢ãªãªãŒã¯ã®åææ¡ä»¶ã§ãã
ã³ãŒãããã¹ãŠãæ£ããå®è¡ãããšããŠãã䜿çšããŠããã©ã€ãã©ãªã«ãã£ãŠãªãŒã¯ãçºçããå¯èœæ§ããããŸãã
å®è¡æã«äœæãããæ°ããã¯ã©ã¹ããŒããŒã䜿çšããŠããã°ã©ã ãäœããããŒãããå Žåã«ã¯ãç¹ã«æ³šæãæãå¿ èŠããããŸãã ããŒããããã¯ã©ã¹ã®1ã€ãžã®ãªã³ã¯ãå°ãªããšã1ã€æ®ã£ãŠããå Žåãã¯ã©ã¹ããŒããŒãšãã®ãã¹ãŠã®ã¯ã©ã¹ã¯ã¡ã¢ãªã«æ®ããŸãã
ã¡ã¢ãªãªãŒã¯ãæ€åºããã«ã¯ãEclipse MATãªã©ã®ç¹å¥ãªããŒã«ã䜿çšããŠãã³ãããã³åæããå¿ èŠããããŸãã
ãµãŒãããŒãã£ã®ã©ã€ãã©ãªã§ã¡ã¢ãªãªãŒã¯ãæ€åºãããå Žåããã®èšäºã§èª¬æãããŠããã¬ã·ãã®ããããã䜿çšããŠãã¡ã¢ãªãªãŒã¯ãæé€ããããšãã§ããŸãã