【问题标题】:string literals and garbage collector in java [duplicate]java中的字符串文字和垃圾收集器[重复]
【发布时间】:2014-05-29 12:58:09
【问题描述】:

更具体地说,我读到在 java 7 中,字符串文字现在存储在堆的主要部分,那么它们是否有资格使用垃圾收集器?

String a ="z";
a = null;

现在对象“z”是被垃圾回收了,还是作为匿名对象仍在字符串池中?

【问题讨论】:

  • 没有。字符串文字不会被垃圾收集。

标签: java garbage-collection


【解决方案1】:

只有当所有包含这些文字的类都被 GC 时,字符串文字才能被 GC

例子:

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());
    }
}

编译这些类,将 Test.class 移动到 d:/test 以便系统类加载器看不到它,然后运行 ​​main。你会看到

X
null

这意味着“X”被 GC 编辑了

【讨论】:

    【解决方案2】:
    • 等价的字符串文字(即使是那些存储在不同类中的 单独的包)将引用同一个 String 对象。

    • 一般来说,字符串文字不符合垃圾回收的条件。 曾经

    • 在运行时创建的字符串总是不同于那些 从字符串文字创建。

    • 您可以通过使用 intern() 方法。

    • 检查字符串是否相等的最好方法是使用 equals() 方法。

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

    请注意,这有点高级 - 您必须了解 String 类的内部工作原理才能理解这一点。

    String 对象将其数据存储在字符数组中。当您获取字符串的子字符串时,通过调用 substring() 方法,创建的新 String 对象不会复制原始字符串的部分数据。相反,它存储对原始字符串基础数据的引用,以及偏移量和长度,以指示新 String 对象代表旧字符串的哪一部分。

    当你有一个很长的字符串(例如你将一个文件的内容读入一个 String 对象)并且你从中取出一个子字符串时,那么 JVM 会将原始字符串的所有数据保留在内存中——甚至如果你丢弃原来的 String 对象,因为用 substring() 创建的 String 对象仍然持有对包含所有数据的整个字符数组的引用。

    为了防止这种内存效率低下,您可以使用子字符串对象显式创建一个新的字符串对象。第二个新字符串对象将从子字符串对象复制数据,但只是您需要的部分。 查看普通版? 注意:代码块中的文本内容会自动换行

    // 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);  
    

    如果您想了解它的具体工作原理,请查看 String 类的源代码,您可以在 JDK 安装目录的 src.zip 文件中找到该源代码。

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

    【讨论】:

    • 你应该停止根据古代文章来回答。当您写答案时,javaranch 文章已经有十年了,即使它是新的,它也是错误的,因为当引用它们的所有类变得无法访问时,字符串文字 can 会被垃圾收集。该 coderanch 文章只有 7 年的历史,并且在发布时有效,但在您发布答案时已过时;从 Java 7 更新 6 开始,子字符串不再与原始字符串共享数组。另一方面,使用String(String) 构造函数构造的String 确实与原始字符串共享数组……
    猜你喜欢
    • 1970-01-01
    • 2013-02-25
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 2013-02-17
    • 2011-01-06
    相关资源
    最近更新 更多