java字符串文字可以被垃圾收集吗?如果是,如何证明?
发布时间:2020-12-15 04:28:06 所属栏目:Java 来源:网络整理
导读:像“abc”这样的 java字符串文字可以被垃圾收集吗?如果是,我们如何以编程方式证明他们是GCed? 解决方法 是的,发布 Java7,如果加载它的类加载器被垃圾收集并且没有对字符串文字的引用,则可以对字符串文字进行垃圾回收. 注意:在Java -8中,您必须调用GC两次
像“abc”这样的
java字符串文字可以被垃圾收集吗?如果是,我们如何以编程方式证明他们是GCed?
解决方法
是的,发布
Java7,如果加载它的类加载器被垃圾收集并且没有对字符串文字的引用,则可以对字符串文字进行垃圾回收.
注意:在Java -8中,您必须调用GC两次以确保ClassLoaders获得GCed(Metaspace .. pfff ..使用不同的GC将无济于事). Case -1 : //ClassLoaders don't get GCed. Code : import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; // main class class TestStringLiteralGC { public static void main(String[] args) throws Exception { Class<?> c1 = new CustomClassLoader().loadClass("Test"); // load class once Class<?> c2 = new CustomClassLoader().loadClass("Test"); // load class again System.out.println("c1 : " + c1); // c1 : class Test System.out.println("c2 : " + c2); // c2 : class Test System.out.println("c1 == c2 :" + (c1 == c2)); //c1 == c2 :false --> So,now we have 2 different class objects for same class. Field f1 = c1.getDeclaredField("s"); // getting field s of c1 f1.setAccessible(true); System.out.println("Identity hashCode of c1.s :"+ System.identityHashCode(f1.get(null))); // Identity hashCode of c1.s :1442407170 Field f2 = c2.getDeclaredField("s"); // getting field s of c2 f2.setAccessible(true); System.out.println("Identity hashCode of c2.s :"+ System.identityHashCode(f2.get(null))); // Identity hashCode of c2.s :1442407170 System.out.println("c1.s == c2.s : " + (f1.get(null) == f2.get(null))); // c1.s == c2.s : true ==> c1.s is the same "instance" as c2.s //Don't make c1 and c2 eligible for GC // So,now,there are still references to "abc" // f1 = null; // c1 = null; // f2 = null; // c2 = null; //call GC explicitly. Yes,twice. Thread.sleep(1000); System.gc(); Thread.sleep(1000); System.gc(); Thread.sleep(1000); // use the same string literal in main. Just to test that the same literal is being used. String s = "abc"; System.out.println("Identity hashCode of mainMethod's s : " + System.identityHashCode(s)); // Identity hashCode of mainMethod's s : 1442407170 ==> Yes. The IDHashcodes are the same } } // Our class which will be loaded class Test { static String s = "abc"; // Our little hero!.The string literal. } //Our custom ClassLoader to load the class "Test" class CustomClassLoader extends ClassLoader { // finalize() is to check if Object is unreachable (and ready for GC) protected void finalize() throws Throwable { System.out.println("CustomClassLoader finalize called.." + this); }; @Override public Class<?> loadClass(String name) throws ClassNotFoundException { if (!name.equals("Test")) { return super.loadClass(name); } try { InputStream in = ClassLoader .getSystemResourceAsStream("Test.class"); byte[] a = new byte[10000]; int len = in.read(a); in.close(); return defineClass(name,a,len); } catch (IOException e) { throw new ClassNotFoundException(); } } } O/P : // NO GC of Classloaders :( c1 : class Test c2 : class Test c1 == c2 :false Identity hashCode of c1.s :1442407170 // Value- 1 Identity hashCode of c2.s :1442407170 // Value -2 c1.s == c2.s : true Identity hashCode of mainMethod's s : 1442407170 // Value -3
Case : 2 //Force GC of ClassLoaders and check again. Code : import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; // main class class TestStringLiteralGC { public static void main(String[] args) throws Exception { Class<?> c1 = new CustomClassLoader().loadClass("Test"); // load class once Class<?> c2 = new CustomClassLoader().loadClass("Test"); // load class again System.out.println("c1 : " + c1); // c1 : class Test System.out.println("c2 : " + c2); // c2 : class Test System.out.println("c1 == c2 :" + (c1 == c2)); //c1 == c2 :false --> So,now we have 2 different class objects for same class. Field f1 = c1.getDeclaredField("s"); // getting field s of c1 f1.setAccessible(true); System.out.println("Identity hashCode of c1.s :"+ System.identityHashCode(f1.get(null))); // Identity hashCode of c1.s :1442407170 Field f2 = c2.getDeclaredField("s"); // getting field s of c2 f2.setAccessible(true); System.out.println("Identity hashCode of c2.s :"+ System.identityHashCode(f2.get(null))); // Identity hashCode of c2.s :1442407170 System.out.println("c1.s == c2.s : " + (f1.get(null) == f2.get(null))); // c1.s == c2.s : true ==> c1.s is the same "instance" as c2.s //Make c1 and c2 eligible for GC // So,there are no references to "abc" f1 = null; c1 = null; f2 = null; c2 = null; //call GC explicitly. Yes,twice. Thread.sleep(1000); System.gc(); Thread.sleep(1000); System.gc(); Thread.sleep(1000); // use the same string literal in main. Just to test that the same literal is being used. String s = "abc"; System.out.println("Identity hashCode of mainMethod's s : " + System.identityHashCode(s)); // Identity hashCode of mainMethod's s : 1118140819 ==> Oh!!. The IDHashcodes are NOT the same } } // Our class which will be loaded class Test { static String s = "abc"; // Our little hero!.The string literal. } //Our custom ClassLoader to load the class "Test" class CustomClassLoader extends ClassLoader { // finalize() is to check if Object is unreachable (and ready for GC) protected void finalize() throws Throwable { System.out.println("CustomClassLoader finalize called.." + this); }; @Override public Class<?> loadClass(String name) throws ClassNotFoundException { if (!name.equals("Test")) { return super.loadClass(name); } try { InputStream in = ClassLoader .getSystemResourceAsStream("Test.class"); byte[] a = new byte[10000]; int len = in.read(a); in.close(); return defineClass(name,len); } catch (IOException e) { throw new ClassNotFoundException(); } } } O/P : c1 : class Test c2 : class Test c1 == c2 :false Identity hashCode of c1.s :1442407170 // Value - 1 Identity hashCode of c2.s :1442407170 // Value - 2 c1.s == c2.s : true CustomClassLoader finalize called..CustomClassLoader@4e25154f // ClassLoader1 GCed CustomClassLoader finalize called..CustomClassLoader@6d06d69c // ClassLoader2 GCed Identity hashCode of mainMethod's s : 1118140819 // Value - 3 ..
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |