【问题标题】:Which among the following String Objects will be ready for garbage collection?以下哪些字符串对象将准备好进行垃圾回收?
【发布时间】:2019-01-26 10:24:50
【问题描述】:

我对字符串常量池和堆有点困惑,我想了解一个字符串对象什么时候有资格进行垃圾回收,所以考虑下面的代码,下面的字符串对象中哪些是准备好的用于java中的垃圾收集?

class Demo{
    public static void main(String args[]){
        String s1 = new String("hey");
        String s2 = s1;
        String s3 = "hey";
        String s4 = "hey";
        String s5 = new String("guys");
        String s6 = "guys";
        String s7 = "guYs";
        s1 = s1.concat("world");
        s7 = null;
        s8 = null;
    }
}

【问题讨论】:

  • 什么时候准备好?

标签: java string object garbage-collection


【解决方案1】:

首先要做的事情:你有变量,比如's1',这些是指针(在java中,'references')。它们就像一张藏宝图:它们本身并不是宝藏,它们只是指明了宝藏所在的方向。

在这个例子中,变量是藏宝图,字符串是宝藏。

上面的例子总共只有7个宝物:

“hey”、“guys”、“guYs”、“world”——这 4 个宝藏是在你的类加载时创建的,因为它们实际上就在你的源代码中。 guy 和 guYs 显然是不同的字符串。

第 5 个宝藏是用 new String("hey") 创建的字符串 - 这会将对宝藏 "hey" 的引用传递给字符串构造函数。所有的构造函数总是创造新的宝藏,即使在这里这是一个毫无意义的练习(字符串不能改变,那有什么意义,对吧?只是,规则是:调用new意味着新的宝藏,所以新的宝藏被创造出来)。现在藏宝图s1指向独特的宝藏,恰好看起来很像宝藏"hey"

s2 = s1 只是在复制一张藏宝图。它通向与 s1 相同的宝藏。

s3 成为指向现有宝藏"hey" 的藏宝图。它与 s1 和 s1 指向的宝藏不同。

s4变成和s3一样的藏宝图。

s5s6s1s3的副本情况:2宝。

s7 与 s3/s4/s6 相同。

然后找到s1宝藏(s1.-点是:拿这张藏宝图找宝藏),然后要求宝藏执行concat的方法,传递给它一个参考不同的宝藏("world")。 concat 的实现最终生成了另一个宝藏(它会读作“heyworld”),并返回一个指向这个新宝藏的藏宝图。然后你扔掉指向"hey" 的藏宝图(但请注意,这根本不会修改s2,它仍然指向"hey" 宝藏),并将其替换为指向"heyworld" 的新藏宝图。

你最后把s7改成空白的藏宝图无处可去,然后写了一个编译器错误s8不存在。

到了代码中,我们来看看这7个宝藏是怎么找到的:

“嘿” - 是的,通过 s3 和 s4。仍然指向它。更重要的是。他们将永远是“可找到的”;您所要做的就是运行这个随时可能发生的主要方法。字面上写入 java 文件的字符串不会消失。

“伙计们”——通过 s6。

"guYs" - 似乎根本找不到,但正如我所说,字符串文字永远不会消失。

“伙计们”的副本:仍然通过 s5。

"heyworld" - 是的,s1 指向它。

副本“嘿”:不,根本找不到。这个宝藏是“无法到达的”。

那么,hey-copy 现在是可垃圾回收的,没有别的了。

7 个宝藏地图 不是可收藏的实体;这些东西存在于堆栈中,并且会在方法退出的那一刻立即消失。

局部变量在堆栈上的工作方式有点奇怪:在类级别它们被转换为未命名的槽。细节很复杂,但可以说在某个位置的插槽中可能仍然存在看似未引用的事物。在方法真正退出之前,您无法确定,此时所有本地变量(在本例中都是藏宝图)立即消失。

此外,在实践中,垃圾收集要等到很久以后才会开始。没有参考的宝物会被长期卡在沙子里。处理它们的最快方法是将它们留在沙子里。只要海滩足够大,就没有必要清理海滩。 GC 的主题要复杂得多,但作为一个快速的教训:它不会在很久以后发生,这很好。

【讨论】:

    【解决方案2】:

    它是这样工作的。

    使用new 运算符创建的每个字符串都会从堆空间中获取内存。所以new String("a") == new String("a")false

    没有new 运算符的文字在字符串池中占有一席之地。所以"a" == "a"true

    使用您的代码,我会说 s1、s2、s5、s7 已准备好进行 GC。 s3, s4, s6 被声明为字面量,因此它们存储在字符串池中。

    【讨论】:

    • s1, s2, s5, s7 都是局部变量。这些存在于堆栈中,垃圾收集的概念根本不适用于它们。
    • 这些变量指向的对象都是不可收集的,因为 OP 写了一个坏例子。显然,一旦方法完全退出(因为任何地方的字段中都没有存储任何内容),所有非字符串池字符串都可以收集。
    • 我认为这个问题的意义更广泛。将局部变量放在堆栈上是对的,但我认为代码只是用于可视化问题/问题的 sn-p。
    • 也许@mohammed-abbas 写另一个,也许用实例字段而不是局部变量......
    猜你喜欢
    • 2015-11-05
    • 1970-01-01
    • 2013-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-17
    相关资源
    最近更新 更多