# HG changeset patch # User coleenp # Date 1536941428 14400 # Node ID 9bf5205655ee3a8199abda638ad685b76a43a6fc # Parent 07ae9da7a230cdb03acfc9ab028340f691a0090e 8210559: ClassLoaderData Symbols can leak Summary: unrefcount the symbol names when the CLD is destroyed Reviewed-by: lfoltan, jiangli, iklam diff -r 07ae9da7a230 -r 9bf5205655ee src/hotspot/share/classfile/classLoaderData.cpp --- a/src/hotspot/share/classfile/classLoaderData.cpp Fri Sep 14 09:00:22 2018 -0700 +++ b/src/hotspot/share/classfile/classLoaderData.cpp Fri Sep 14 12:10:28 2018 -0400 @@ -769,6 +769,14 @@ if (_deallocate_list != NULL) { delete _deallocate_list; } + + // Decrement refcounts of Symbols if created. + if (_name != NULL) { + _name->decrement_refcount(); + } + if (_name_and_id != NULL) { + _name_and_id->decrement_refcount(); + } } // Returns true if this class loader data is for the app class loader diff -r 07ae9da7a230 -r 9bf5205655ee src/hotspot/share/prims/whitebox.cpp --- a/src/hotspot/share/prims/whitebox.cpp Fri Sep 14 09:00:22 2018 -0700 +++ b/src/hotspot/share/prims/whitebox.cpp Fri Sep 14 12:10:28 2018 -0400 @@ -178,6 +178,15 @@ return closure.found(); WB_END +WB_ENTRY(jint, WB_GetSymbolRefcount(JNIEnv* env, jobject unused, jstring name)) + oop h_name = JNIHandles::resolve(name); + if (h_name == NULL) return false; + Symbol* sym = java_lang_String::as_symbol(h_name, CHECK_0); + TempNewSymbol tsym(sym); // Make sure to decrement reference count on sym on return + return (jint)sym->refcount(); +WB_END + + WB_ENTRY(void, WB_AddToBootstrapClassLoaderSearch(JNIEnv* env, jobject o, jstring segment)) { #if INCLUDE_JVMTI ResourceMark rm; @@ -1982,7 +1991,6 @@ return (jint) SystemDictionary::pd_cache_table()->removed_entries_count(); WB_END - #define CC (char*) static JNINativeMethod methods[] = { @@ -1996,6 +2004,7 @@ {CC"getHeapSpaceAlignment", CC"()J", (void*)&WB_GetHeapSpaceAlignment}, {CC"getHeapAlignment", CC"()J", (void*)&WB_GetHeapAlignment}, {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, + {CC"getSymbolRefcount", CC"(Ljava/lang/String;)I", (void*)&WB_GetSymbolRefcount }, {CC"parseCommandLine0", CC"(Ljava/lang/String;C[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", (void*) &WB_ParseCommandLine diff -r 07ae9da7a230 -r 9bf5205655ee test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java --- a/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java Fri Sep 14 09:00:22 2018 -0700 +++ b/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java Fri Sep 14 12:10:28 2018 -0400 @@ -23,6 +23,7 @@ /* * @test UnloadTest + * @bug 8210559 * @requires vm.opt.final.ClassUnloading * @modules java.base/jdk.internal.misc * @library /runtime/testlibrary /test/lib @@ -30,7 +31,7 @@ * @build sun.hotspot.WhiteBox test.Empty * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI UnloadTest + * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xlog:class+unload=debug UnloadTest */ import sun.hotspot.WhiteBox; @@ -60,8 +61,16 @@ ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here"); + String loaderName = cl.getName(); + int loadedRefcount = wb.getSymbolRefcount(loaderName); + System.out.println("Refcount of symbol " + loaderName + " is " + loadedRefcount); + cl = null; c = null; o = null; ClassUnloadCommon.triggerUnloading(); ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded"); + + int unloadedRefcount = wb.getSymbolRefcount(loaderName); + System.out.println("Refcount of symbol " + loaderName + " is " + unloadedRefcount); + ClassUnloadCommon.failIf(unloadedRefcount != (loadedRefcount - 1), "Refcount must be decremented"); } } diff -r 07ae9da7a230 -r 9bf5205655ee test/hotspot/jtreg/runtime/testlibrary/ClassUnloadCommon.java --- a/test/hotspot/jtreg/runtime/testlibrary/ClassUnloadCommon.java Fri Sep 14 09:00:22 2018 -0700 +++ b/test/hotspot/jtreg/runtime/testlibrary/ClassUnloadCommon.java Fri Sep 14 12:10:28 2018 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ .map(Paths::get) .map(ClassUnloadCommon::toURL) .toArray(URL[]::new); - return new URLClassLoader(urls) { + return new URLClassLoader("ClassUnloadCommonClassLoader", urls, new ClassUnloadCommon().getClass().getClassLoader()) { @Override public Class loadClass(String cn, boolean resolve) throws ClassNotFoundException diff -r 07ae9da7a230 -r 9bf5205655ee test/lib/sun/hotspot/WhiteBox.java --- a/test/lib/sun/hotspot/WhiteBox.java Fri Sep 14 09:00:22 2018 -0700 +++ b/test/lib/sun/hotspot/WhiteBox.java Fri Sep 14 12:10:28 2018 -0400 @@ -103,6 +103,7 @@ return isClassAlive0(name.replace('.', '/')); } private native boolean isClassAlive0(String name); + public native int getSymbolRefcount(String name); private native boolean isMonitorInflated0(Object obj); public boolean isMonitorInflated(Object obj) {