在使用”new String(..)”时创建了无法访问的文字常量?

huangapple go评论73阅读模式
英文:

Unreachable literal created during "new String(..)"?

问题

所以new String("abc");在堆中创建了一个对象,并在字符串池中创建了文字"abc",根据我找到的许多答案。由于使用了new关键字,字符串池中不应该有对字符串文字的引用。

这是否意味着 -

a. 在下一次运行中,文字(假设后续没有创建对该文字的其他引用)将会被垃圾回收?

b. 如果(对于问题a的答案是)肯定的,JVM似乎可以在对象创建后立即释放字符串池中的文字,而不是等待垃圾回收。为什么不这样做?

c. 如果(对于问题a的答案是)否定的,对于一个无法访问的文字而言,不被垃圾回收的原因是什么?

英文:

So a new String("abc"); creates an object in Heap & a literal "abc" in the String pool as per many of the answers I found. Since the new keyword was used, there should be no references to the String literal in the pool.

Does this mean -

a. The literal will be GC'ed in the next run (assuming no other references were created to the literal later on)?

b. If (the answer to a is) yes, it sounds fairly easy for JVM to free the literal in the pool as soon as the object is created, instead of waiting for GC. Why is this not done?

c. If (the answer to a is) no, what would be the reason for the an unreachable literal to not be GC'ed?

答案1

得分: 2

> 由于使用了 new 关键字,字符串池中不应该有对字符串字面量的引用。

这是不正确的。可能有一个可达的引用指向与字面量对应的 String 对象。我记得这个引用存储在保存类静态字段的同一个“框架”中。在实际情况中,只要垃圾收集器不会卸载封闭类(通常几乎不会发生),这个引用将继续是可达的。

所以答案是:

> a. 字面量会在下一次运行中被垃圾回收吗?(假设后续没有创建对该字面量的其他引用)

不会。

> c. 如果(问题 a 的答案是)不会,那么一个不可达的字面量不会被垃圾回收的原因是什么?

与字面量对应的 String 对象是不不可达的。例如,如果存在任何可能导致可以再次执行 new String("abc") 语句的情况,它必须是可达的。

由于在 JVM 运行时难以确定一条语句(在编译时确定为可达的)在运行时是否会被执行多次,而且在这样做时几乎没有性能优势,运行时会假设所有字符串字面量在定义它们的 Java 类的生命周期内都需要是可达的。

最后,正如 @Holger 指出的,字符串字面量对象何时变得不可达并没有实际意义。如果需要,它们以某种形式存在。那才是真正重要的。


<sup>1 - 实际行为高度依赖于实现。在早期的 JVM 中,类字面量的 String 对象会被急切地池化。后来这种情况改变为延迟池化。甚至可以在每次使用字符串字面量时重新池化一个 String 对象,尽管这在一般情况下非常低效。然后我们需要考虑优化器可能执行的各种操作。例如,它可能注意到字面量的 String 对象从未逃逸,并且以不需要实际池化的方式使用。或者它可能注意到整个表达式可以被优化掉。</sup>

<sup>2 - 我指的是类。与 Class 对象对应的东西。不是这些类的实例。</sup>

英文:

> Since the new keyword was used, there should be no references to the String literal in the pool.

That is not correct. There is probably<sup>1</sup> a reachable reference to the String object that corresponds to the literal. My recollection is that the reference is stored in the same "frame" that holds the static fields for the class. In practice, this reference will continue to be reachable until the enclosing class is unloaded by the garbage collector. (That typically never happens.)

So the answers are:

> a. The literal will be GC'ed in the next run (assuming no other references were created to the literal later on)?

No.

> c. If (the answer to a is) no, what would be the reason for the an unreachable literal to not be GC'ed?

The String object corresponding to the literal is NOT unreachable. For example, it needs to be reachable if there is any possibility that the new String(&quot;abc&quot;) statement could be executed again.

Since it is difficult for the JVM runtime to determine that a statement (that was determined to be reachable at compile time) won't be executed more than once at runtime, and since there is little performance benefit in doing that, the runtime assumes that all string literals need to be reachable for the lifetime of the Java classes<sup>2</sup> that define them.

Finally, as @Holger points out, it makes no practical difference when String literal objects become unreachable. We know that they will be present (in some form) if they are needed. That's all that really matters.


<sup>1 - The actual behavior is highly implementation dependent. In early JVMs, the String objects for class literals were interned eagerly. Later on this changed to lazy interning. It would even be possible to re-intern a String object every time the string literal is used, though this would be very inefficient in general. Then we need to consider various things that optimizer could do. For example, it could notice that the String object for the literal never escapes and is used in a way that doesn't actually require interning. Or it could notice that the entire expression could be optimized away.</sup>

<sup>2 - I mean classes. The things that correspond to a Class object. Not instances of those classes.</sup>

答案2

得分: 1

因为 new String("abc"); 是一个对象而且没有被放入常量池中,所以它会在下一次垃圾回收运行时被回收。

  • 然而,由于各种性能原因和空间的可用性,垃圾回收并不会立即运行以收集这个字符串对象。

  • 使用 System.gc(); 也不能保证它会运行(这只是向垃圾回收建议运行)。

垃圾回收的运行有许多原因,以下是其中一些(还取决于虚拟机):

特定代的内存分配超出限制。
堆分配或对象存在达到阈值等。

英文:

Since new String("abc"); is object and not interned it will be garbage collected in next GC run.

  • However GC won't be immediately running just to collect this string object due to various performance reasons & availability of space.

  • Using System.gc(); also doesn't guarantee that it'll run (this is just suggestion to the GC to run.)

GC runs with many reason few are like below (also depends on VM)

More Memory allocation in specific generation is failling.
Heap allocation Or Objects presence reaching threshold etc.

huangapple
  • 本文由 发表于 2020年8月16日 12:22:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/63433119.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定