我有一个提供Resource
类的库,应该由 Java 9 清理Cleaner
。
import java.lang.ref.Cleaner;
public class Resource {
static Cleaner CLEANER = Cleaner.create();
static class CleanerHandler implements Runnable {
private final String name;
CleanerHandler(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("Running Cleaner for " + name);
}
}
public Resource(String name) {
CLEANER.register(this, new CleanerHandler(name));
}
}
假设我有一个CleanerMain
使用Resource
. 应用程序会创建两个Resource
,一个供本地使用,另一个存储在静态字段中。
public class CleanerMain {
private static Resource SINGLETON = new Resource("global_resource");
public static void main(String[] arguments) {
Resource localResource = new Resource("local_resource");
}
}
应用程序将被加载到一个ClassLoader
(例如作为一个 OSGi 模块或一个 WAR 文件)中。我希望ClassLoader
应用程序终止后将被卸载。
但是,ClassLoader
从来没有卸载过。我从未见过日志Running Cleaner for global_resource
,但Running Cleaner for local_resource
会显示。
可以通过启动sbt shell 并执行来重现该问题runMain CleanerMain
// build.sbt
TaskKey[Unit]("gc", "Perform System.gc()") := {
System.gc()
}
注意我提供了一个 sbt 任务来执行System.gc()
。但它并不能帮助 JVM 收集 global_resource 或卸载 ClassLoader。
$ sbt -J-Xlog:class+unload=info
[4.268s][info][class,unload] unloading class $1dd3210e9cda6e6faf3e$ 0x00000007c0704c28
[info] Loading settings from idea.sbt ...
[info] Loading global plugins from /Users/twer/.sbt/1.0/plugins
[6.938s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2317/1862022854 0x00000007c096e828
[6.938s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2314/1263423349 0x00000007c096dc28
[6.938s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2313/1416148598 0x00000007c096d828
[6.938s][info][class,unload] unloading class jdk.internal.reflect.GeneratedConstructorAccessor5 0x00000007c092d028
[6.938s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2204/2088963974 0x00000007c092cc28
[6.938s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2205/832626395 0x00000007c092c828
[6.938s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2203/247832656 0x00000007c092c028
[6.938s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2202/1272449757 0x00000007c092c428
[6.938s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2200/573210156 0x00000007c092bc28
[6.938s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2201/1054035589 0x00000007c092b828
[6.938s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2199/864020513 0x00000007c092b428
[6.938s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2197/1730739373 0x00000007c092a828
[6.938s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2195/1889391840 0x00000007c092ac28
[6.938s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2193/1883646233 0x00000007c0929828
[6.938s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2196/834352185 0x00000007c0929428
[6.938s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2191/1271342924 0x00000007c0929c28
[6.938s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2194/964794066 0x00000007c092a028
[6.938s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2190/2077351835 0x00000007c092a428
[6.938s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2189/1898558699 0x00000007c0928c28
[6.938s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2188/1200655829 0x00000007c0928828
[6.938s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2187/2122434745 0x00000007c0928428
[6.938s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2186/2119841115 0x00000007c0928028
[6.938s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2184/1842386909 0x00000007c0927428
[6.938s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2182/1696943117 0x00000007c0927028
[6.938s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2183/1035863485 0x00000007c0927828
[6.938s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2181/863632802 0x00000007c0926c28
[6.938s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2154/10566077 0x00000007c08eec28
[6.938s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2152/1127241241 0x00000007c08ee428
[6.938s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2150/1510063672 0x00000007c08edc28
[6.938s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2148/1860233843 0x00000007c08ed428
[6.938s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2146/1286502317 0x00000007c08ecc28
[6.938s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2142/829754298 0x00000007c08ebc28
[6.938s][info][class,unload] unloading class sbt.librarymanagement.DependencyFilterExtra$$anon$2$$Lambda$2140/1782115063 0x00000007c08eb428
[6.938s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2138/1768513715 0x00000007c08eac28
[6.938s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2136/27449893 0x00000007c08ea428
[6.938s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2134/204419489 0x00000007c08e9c28
[6.938s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2132/538764795 0x00000007c08e9028
[6.938s][info][class,unload] unloading class sbt.librarymanagement.DependencyFilter$$Lambda$2130/514769339 0x00000007c08e7828
[6.938s][info][class,unload] unloading class sbt.io.IO$$$Lambda$1997/1978868777 0x00000007c0875c28
[6.938s][info][class,unload] unloading class sbt.io.IO$$$Lambda$1995/1414642509 0x00000007c0875428
[6.938s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1812/827059833 0x00000007c0828c28
[6.938s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1810/1274501898 0x00000007c0828428
[6.938s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1808/427763295 0x00000007c0827c28
[6.938s][info][class,unload] unloading class java.lang.invoke.LambdaForm$MH/2046367300 0x00000007c0827428
[6.938s][info][class,unload] unloading class java.lang.invoke.LambdaForm$DMH/241446552 0x00000007c0826c28
[6.938s][info][class,unload] unloading class java.lang.invoke.LambdaForm$DMH/1629192413 0x00000007c0826428
[6.938s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1806/1846159181 0x00000007c0825c28
[6.938s][info][class,unload] unloading class java.lang.invoke.LambdaForm$DMH/1370803139 0x00000007c0825028
[6.938s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1803/555261988 0x00000007c0824828
[6.938s][info][class,unload] unloading class sbt.Info$$Lambda$1799/2128443263 0x00000007c0823828
[6.938s][info][class,unload] unloading class sbt.Info$$Lambda$1798/1604599396 0x00000007c0823428
[6.938s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1796/242303008 0x00000007c0822c28
[6.938s][info][class,unload] unloading class sbt.InputTask$$$Lambda$1794/495384449 0x00000007c0822428
[6.938s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1792/1919993452 0x00000007c0821428
[6.938s][info][class,unload] unloading class sbt.std.FullInstance$$$Lambda$1789/1632362915 0x00000007c081f828
[6.939s][info][class,unload] unloading class sbt.Project$RichTaskSessionVar$$Lambda$1787/818768380 0x00000007c0820c28
[6.939s][info][class,unload] unloading class sbt.Project$RichTaskSessionVar$$Lambda$1786/1707177614 0x00000007c081fc28
[6.939s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1785/1406446596 0x00000007c081e428
[6.939s][info][class,unload] unloading class sbt.InputTask$$Lambda$1779/1575782527 0x00000007c081b828
[6.939s][info][class,unload] unloading class sbt.internal.Load$$$Lambda$1776/911414257 0x00000007c081ac28
[6.939s][info][class,unload] unloading class sbt.Scoped$DefinableTask$$Lambda$1742/718898651 0x00000007c0809028
[6.939s][info][class,unload] unloading class sbt.Scoped$DefinableTask$$Lambda$1741/2141277569 0x00000007c0808c28
[6.939s][info][class,unload] unloading class sbt.librarymanagement.CrossVersionFunctions$$Lambda$1727/1915497383 0x00000007c0804c28
[6.939s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1722/1222769759 0x00000007c0803828
[6.939s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1721/839493008 0x00000007c0803428
[6.939s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1719/1185812006 0x00000007c0802c28
[6.939s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1718/2007085583 0x00000007c0802828
[6.939s][info][class,unload] unloading class sbt.internal.util.BasicAttributeMap$$Lambda$1712/388524031 0x00000007c0800c28
[6.939s][info][class,unload] unloading class sbt.std.TaskExtra$$anon$4$$Lambda$1710/584011560 0x00000007c07ff828
[6.939s][info][class,unload] unloading class sbt.std.TaskExtra$$anon$4$$Lambda$1708/688753695 0x00000007c07ff428
[6.939s][info][class,unload] unloading class sbt.std.TaskExtra$$Lambda$1707/1300772899 0x00000007c07fec28
[6.939s][info][class,unload] unloading class sbt.internal.util.EvaluateSettings$INode$$Lambda$1701/1287105801 0x00000007c07fd428
[6.939s][info][class,unload] unloading class sbt.internal.util.EvaluateSettings$INode$$Lambda$1699/1216884928 0x00000007c07fcc28
[info] Loading project definition from /Users/twer/workspace/static-cleaner-test/project
[info] Loading settings from build.sbt ...
[info] Set current project to static-cleaner-test (in build file:/Users/twer/workspace/static-cleaner-test/)
[info] sbt server started at local:///Users/twer/.sbt/1.0/server/ac09f3126a948ca68d3f/sock
sbt:static-cleaner-test> runMain CleanerMain
[warn] Multiple main classes detected. Run 'show discoveredMainClasses' to see the list
[info] Running CleanerMain
[success] Total time: 0 s, completed Jan 24, 2018, 3:11:41 PM
sbt:static-cleaner-test> gc
[11.835s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2778/1611088935 0x00000007c0a88428
[11.835s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2776/1333727936 0x00000007c0a87c28
[11.835s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2580/1413550615 0x00000007c0a14828
[11.835s][info][class,unload] unloading class sbt.librarymanagement.CrossVersionFunctions$$Lambda$2436/153217649 0x00000007c08eac28
Running Cleaner for local_resource
[success] Total time: 0 s, completed Jan 24, 2018, 3:11:43 PM
sbt:static-cleaner-test> gc
[success] Total time: 0 s, completed Jan 24, 2018, 3:11:44 PM
sbt:static-cleaner-test> gc
[success] Total time: 0 s, completed Jan 24, 2018, 3:11:45 PM
如果我删除Resource SINGLETON
.
public class CleanerMain2 {
public static void main(String[] arguments) {
Resource localResource = new Resource("local_resource");
}
}
然后 JVM 能够卸载ClassLoader
.
$ sbt -J-Xlog:class+unload=info
[4.504s][info][class,unload] unloading class $1dd3210e9cda6e6faf3e$ 0x00000007c0704c28
[info] Loading settings from idea.sbt ...
[info] Loading global plugins from /Users/twer/.sbt/1.0/plugins
[7.296s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2312/1094459247 0x00000007c096d428
[7.296s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2310/1320570298 0x00000007c096cc28
[7.296s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2307/2112293268 0x00000007c096c428
[7.296s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2200/640141239 0x00000007c092b828
[7.296s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2198/1336665608 0x00000007c092b028
[7.296s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2199/558583552 0x00000007c092ac28
[7.296s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2196/1021158914 0x00000007c092a828
[7.296s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2194/1215619972 0x00000007c092bc28
[7.296s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2195/327444195 0x00000007c092b428
[7.296s][info][class,unload] unloading class sbt.io.Hash$$$Lambda$2193/244510474 0x00000007c092a028
[7.296s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2192/398188748 0x00000007c0929c28
[7.296s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2186/1663387063 0x00000007c0928828
[7.296s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2191/1336927537 0x00000007c0928428
[7.296s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2190/1368378621 0x00000007c0928c28
[7.296s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2185/1268018082 0x00000007c0929428
[7.296s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2187/1280016085 0x00000007c0928028
[7.296s][info][class,unload] unloading class sbt.internal.inc.Stamper$$$Lambda$2188/2044671837 0x00000007c0929828
[7.296s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2184/1598564708 0x00000007c0927c28
[7.296s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2183/598636885 0x00000007c0927428
[7.296s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2182/1163103608 0x00000007c0927028
[7.296s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2178/1097339756 0x00000007c0926c28
[7.296s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2180/1776103111 0x00000007c0927828
[7.296s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2181/427560339 0x00000007c0926828
[7.296s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2179/1116506356 0x00000007c0926428
[7.297s][info][class,unload] unloading class scala.collection.parallel.Task$$Lambda$2176/1931959341 0x00000007c0925c28
[7.297s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2149/1632104444 0x00000007c08edc28
[7.297s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2147/951655327 0x00000007c08ed428
[7.297s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2145/906184298 0x00000007c08ecc28
[7.297s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2143/353174638 0x00000007c08ec428
[7.297s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2141/1871103024 0x00000007c08ebc28
[7.297s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2137/2016625837 0x00000007c08eac28
[7.297s][info][class,unload] unloading class sbt.librarymanagement.DependencyFilterExtra$$anon$2$$Lambda$2135/440876376 0x00000007c08ea028
[7.297s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2133/1964977506 0x00000007c08e9c28
[7.297s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2131/1060080941 0x00000007c08e9428
[7.297s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2129/243387300 0x00000007c08e8c28
[7.297s][info][class,unload] unloading class sbt.librarymanagement.RichUpdateReport$$Lambda$2127/918282376 0x00000007c08e8028
[7.297s][info][class,unload] unloading class sbt.librarymanagement.DependencyFilter$$Lambda$2125/118535508 0x00000007c08de828
[7.297s][info][class,unload] unloading class scala.collection.generic.Shrinkable$$Lambda$2008/1613248130 0x00000007c087a428
[7.297s][info][class,unload] unloading class sbt.io.IO$$$Lambda$1991/485981493 0x00000007c086cc28
[7.297s][info][class,unload] unloading class sbt.io.IO$$$Lambda$1989/238294722 0x00000007c086c428
[7.297s][info][class,unload] unloading class sbt.internal.BuildStreams$$$Lambda$1983/156325408 0x00000007c086a828
[7.297s][info][class,unload] unloading class sbt.internal.BuildStreams$$$Lambda$1982/1681481604 0x00000007c0869428
[7.297s][info][class,unload] unloading class sbt.internal.BuildStreams$$$Lambda$1979/719766168 0x00000007c0868828
[7.297s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1793/2099570980 0x00000007c0823428
[7.297s][info][class,unload] unloading class java.lang.invoke.LambdaForm$MH/1981037155 0x00000007c0822428
[7.297s][info][class,unload] unloading class java.lang.invoke.LambdaForm$DMH/84883684 0x00000007c0821c28
[7.297s][info][class,unload] unloading class java.lang.invoke.LambdaForm$DMH/1034705834 0x00000007c0821028
[7.297s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1785/1570117727 0x00000007c081fc28
[7.297s][info][class,unload] unloading class sbt.InputTask$$Lambda$1780/548480316 0x00000007c081e428
[7.297s][info][class,unload] unloading class sbt.Info$$Lambda$1768/2099487642 0x00000007c081a428
[7.297s][info][class,unload] unloading class sbt.SessionVar$$$Lambda$1766/1466250819 0x00000007c0819828
[7.297s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1763/73374128 0x00000007c0817828
[7.297s][info][class,unload] unloading class sbt.librarymanagement.CrossVersionFunctions$$Lambda$1732/1513402381 0x00000007c0807028
[7.297s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1728/90739503 0x00000007c0805828
[7.297s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1726/1351789811 0x00000007c0805028
[7.297s][info][class,unload] unloading class sbt.Defaults$$$Lambda$1724/1188000171 0x00000007c0804828
[7.297s][info][class,unload] unloading class sbt.std.TaskExtra$$$Lambda$1717/666540636 0x00000007c0802c28
[7.297s][info][class,unload] unloading class sbt.internal.util.BasicAttributeMap$$Lambda$1715/585322260 0x00000007c0802028
[7.297s][info][class,unload] unloading class sbt.internal.util.BasicAttributeMap$$Lambda$1714/965150718 0x00000007c0800c28
[7.297s][info][class,unload] unloading class sbt.std.TaskExtra$$Lambda$1712/1301296031 0x00000007c0800028
[7.297s][info][class,unload] unloading class sbt.std.TaskExtra$$Lambda$1711/778734195 0x00000007c07ffc28
[7.297s][info][class,unload] unloading class sbt.std.TaskExtra$$Lambda$1710/1045788057 0x00000007c07ff828
[7.297s][info][class,unload] unloading class sbt.std.TaskExtra$$anon$4$$Lambda$1706/2089129482 0x00000007c07ff028
[7.297s][info][class,unload] unloading class sbt.std.TaskExtra$$anon$4$$Lambda$1707/545992152 0x00000007c07fe828
[7.297s][info][class,unload] unloading class sbt.internal.util.EvaluateSettings$INode$$Lambda$1701/2137554850 0x00000007c07fd428
[7.297s][info][class,unload] unloading class sbt.internal.util.EvaluateSettings$INode$$Lambda$1699/1907331047 0x00000007c07fcc28
[info] Loading project definition from /Users/twer/workspace/static-cleaner-test/project
[info] Loading settings from build.sbt ...
[info] Set current project to static-cleaner-test (in build file:/Users/twer/workspace/static-cleaner-test/)
[info] sbt server started at local:///Users/twer/.sbt/1.0/server/ac09f3126a948ca68d3f/sock
sbt:static-cleaner-test> runMain CleanerMain2
[info] Running CleanerMain2
[success] Total time: 1 s, completed Jan 24, 2018, 3:19:11 PM
Running Cleaner for local_resource
sbt:static-cleaner-test> gc
[12.734s][info][class,unload] unloading class Resource$CleanerHandler 0x00000007c0a92c08
[12.734s][info][class,unload] unloading class Resource 0x00000007c0a92a18
[12.734s][info][class,unload] unloading class CleanerMain2 0x00000007c0a92828
[12.734s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2770/75632023 0x00000007c0a7f828
[12.734s][info][class,unload] unloading class sbt.Classpaths$$$Lambda$2768/1059168902 0x00000007c0a7f028
[12.734s][info][class,unload] unloading class sbt.librarymanagement.CrossVersionFunctions$$Lambda$2432/1035741625 0x00000007c08e8c28
[success] Total time: 0 s, completed Jan 24, 2018, 3:19:13 PM
sbt:static-cleaner-test> gc
[success] Total time: 0 s, completed Jan 24, 2018, 3:19:15 PM
我也试过了finalize
。与, 不同Cleaner
,finalize
不会阻止类卸载。不幸的是,它在 Java 9 中已被弃用。
那么,确保在 Java 9 中清理静态本机资源的正确方法是什么?
- 作为库作者,我应该创建 static
Cleaner
吗? - 作为应用程序开发人员,我应该创建静态资源吗?
- 作为应用服务器开发人员,我应该如何卸载模块?