string literals and garbage collector in java [dup

2019-08-15 07:21发布

问题:

This question already has an answer here:

  • Garbage collection of String literals 4 answers

To be more specific I've read that in java 7 string literal are now stored in the main part of the heap so, do they become eligible for garbage collector?

String a ="z";
a = null;

Now does the object "z" get garbage collected,or still in the string pool as an anonymous object ?

回答1:

String literals can only be GCed when all classes contaning these literals are GCed which in turn can only happen if ClassLoaders which loaded these classes are GCed.

Example:

public interface I {
    String getString();
}

public class Test2 implements I {
    String s = "X";
    @Override
    public String getString() {
        return s;
    }
}

public class Test implements I {
    String s = "X";
    @Override
    public String getString() {
        return s;
    }
}

public class Test1 {

    public static void main(String[] args) throws Exception {
        ClassLoader cl = new URLClassLoader(new URL[] {new URL("file:d:/test/")});
        I i = (I)cl.loadClass("Test").newInstance();
        WeakReference w = new WeakReference(i.getString()); //weak ref to "X" literal
        i = null;
        cl = null;
        System.out.println(w.get());
        System.gc();
        Thread.sleep(1000);
        System.out.println(w.get());
    }
}

compile these classes, move Test.class to d:/test so that system class loader cannot see it, then run main. You will see

X
null

which means "X" was GC ed



回答2:

  • Equivalent String Literals (even those stored in separate classes in separate packages) will refer to the same String object.

  • In general, String Literals are not eligible for garbage collection. Ever.

  • Strings created at run-time will always be distinct from those created from String Literals.

  • You can reuse String Literals with run-time Strings by utilizing the intern() method.

  • The best way to check for String equality is to use the equals() method.

Source :
http://www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html

Note that this is a bit advanced - you have to know something about the inner workings of class String to understand this.

A String objects stores its data in a character array. When you take a substring of a string, by calling the substring() method, then the new String object that is created does not copy part of the data of the original string. Instead, it stores a reference to the underlying data of the original string, along with an offset and length to indicate what part of the old string the new String object represents.

When you have a very long string (for example you read the contents of a file into a String object) and you take a substring out of it, then the JVM will retain all the data of the original string in memory - even if you discard the original String object, because the String object created with substring() still holds a reference to the whole character array with all the data.

To prevent this memory inefficiency, you can explicitly create a new String object using the substring object. That second new String object will copy the data from the substring object, but just the part that you need. view plainprint? Note: Text content in the code blocks is automatically word-wrapped

// Suppose this contains 100K characters read from a file  
String largeString = ...;  

// This will refer to the 100K char array from largeString, keeping the whole buffer in memory  
// even though sub represents only 20 characters  
String sub = largeString.substring(80, 100);  

// This will copy the 20 characters from sub into a new buffer, so that the whole 100K buffer doesn't need to be kept  
String sub2 = new String(sub);  

If you want to see how exactly it works, then have a look at the source code of class String, which you can find in the file src.zip in your JDK installation directory.

Source :
http://www.coderanch.com/t/542489/java/java/string-literal-String-Object