I'm reading about WeakReference
in wikipedia and I saw this code
我在*上看到了WeakReference,我看到了这个代码
public class ReferenceTest {
public static void main(String[] args) throws InterruptedException {
WeakReference r = new WeakReference(new String("I'm here"));
WeakReference sr = new WeakReference("I'm here");
System.out.println("before gc: r=" + r.get() + ", static=" + sr.get());
System.gc();
Thread.sleep(100);
// only r.get() becomes null
System.out.println("after gc: r=" + r.get() + ", static=" + sr.get());
}
}
When It runs this is the result
当它运行时,这就是结果
before gc: r=I'm here, static=I'm here
在gc: r=I在这里之前,static=I在这里
after gc: r=null, static=I'm here
在gc: r=null之后,static=I在这里
sr
and r
variable are both referring string objects. r
is now garbage collected but, why sr
didn't garbage collected after calling garbage collector?
sr和r变量都是引用字符串对象。r现在是垃圾收集,但是,为什么在调用垃圾收集器之后,sr没有垃圾收集呢?
I'm just curious how this happened.
我只是好奇这是怎么发生的。
3 个解决方案
#1
6
It is NOT because of string pooling per se.
这并不是因为字符串池本身。
The real reason is that the ReferenceTest
class has an implicit hard reference to the String object that represents the "I'm here"
literal. That hard reference means that the weak reference in sr
won't be broken by the garbage collection1.
真正的原因是ReferenceTest类对表示“我在这里”的字符串对象有一个隐式的硬引用。这个硬引用意味着在sr中弱引用不会被垃圾收集破坏。
In fact:
事实上:
-
The implicit reference would be necessary, even if String objects corresponding to literals weren't pooled. (They are pooled ... the JLS effectively requires this ... but I'm saying the references would required even if they weren't. The alternative would be for Java to mint a fresh String object each time a string literal expression was evaluated. That would be horribly inefficient!!)
隐式引用是必要的,即使与文字对应的字符串对象没有被合并。(它们汇集……JLS有效地要求……但我说的是,即使没有推荐信,也需要推荐信。另一种选择是Java在每次计算字符串文字表达式时创建一个新的字符串对象。那将是非常低效的!!
-
The string pool internally uses a form of weak reference ... so that unreferenced interned strings can be garbage collected. If that weren't the case, then every new interned string would be a memory leak.
字符串池内部使用弱引用的形式……这样,未引用的interned字符串就可以被垃圾收集。如果不是这样,那么每一个新插入的字符串都是内存泄漏。
Anyway ... if you carefully construct a string without using a string literal and intern it, like this:
无论如何……如果您小心地构造一个字符串而不使用字符串文字,并对其进行实习,如下所示:
char[] chars = {'a', 'b', 'c'};
WeakReference r = new WeakReference(new String(chars).intern());
... you should find that the weak reference is (eventually) broken. (It might take a couple of GC cycles though.)
…你应该发现弱引用(最终)被破坏了。(不过可能需要几个GC周期。)
1 - In theory, causing the class to be unloaded and garbage collected could get rid of the last reachable hard reference to that String literal. However, if that happened in this case, you'd be past the point at which you'd be able to observe the state of the WeakReference object. At least, in with your example code. Besides, unless you boot your JVM with a custom class loader, I don't think it would be possible to cause the unloading of the entrypoint class. It's not the kind of thing that is easy, or useful to do.
1 -理论上,导致类被卸载和垃圾收集可以消除对字符串字面量的最后可访问的硬引用。但是,如果在这种情况下发生这种情况,那么您就可以通过观察WeakReference对象的状态。至少,在示例代码中。此外,除非您使用自定义类装入器引导JVM,否则我认为不可能导致entrypoint类的卸载。这不是一件容易或有用的事情。
#2
1
It is becuase of string pooling.When you create string with new operator, it will get created in pool and available for normal garbage collection.But when you define string as literal, it will get created in string pool, and it wont get garbage collected with normal gc operation
这是因为字符串池。当您使用new操作符创建字符串时,它将在池中创建,并可用于正常的垃圾收集。但是,当您将字符串定义为文字时,它将在字符串池中创建,并且不会通过正常的gc操作收集垃圾
#3
-1
Static variables are Garbage Collected only when the class is unloaded. Therefore you can see that the value of the static variable is still printed even after you manually triggered garbage collection.
静态变量只有在类被卸载时才被收集。因此,您可以看到,即使在手动触发垃圾收集之后,静态变量的值仍然被打印出来。
#1
6
It is NOT because of string pooling per se.
这并不是因为字符串池本身。
The real reason is that the ReferenceTest
class has an implicit hard reference to the String object that represents the "I'm here"
literal. That hard reference means that the weak reference in sr
won't be broken by the garbage collection1.
真正的原因是ReferenceTest类对表示“我在这里”的字符串对象有一个隐式的硬引用。这个硬引用意味着在sr中弱引用不会被垃圾收集破坏。
In fact:
事实上:
-
The implicit reference would be necessary, even if String objects corresponding to literals weren't pooled. (They are pooled ... the JLS effectively requires this ... but I'm saying the references would required even if they weren't. The alternative would be for Java to mint a fresh String object each time a string literal expression was evaluated. That would be horribly inefficient!!)
隐式引用是必要的,即使与文字对应的字符串对象没有被合并。(它们汇集……JLS有效地要求……但我说的是,即使没有推荐信,也需要推荐信。另一种选择是Java在每次计算字符串文字表达式时创建一个新的字符串对象。那将是非常低效的!!
-
The string pool internally uses a form of weak reference ... so that unreferenced interned strings can be garbage collected. If that weren't the case, then every new interned string would be a memory leak.
字符串池内部使用弱引用的形式……这样,未引用的interned字符串就可以被垃圾收集。如果不是这样,那么每一个新插入的字符串都是内存泄漏。
Anyway ... if you carefully construct a string without using a string literal and intern it, like this:
无论如何……如果您小心地构造一个字符串而不使用字符串文字,并对其进行实习,如下所示:
char[] chars = {'a', 'b', 'c'};
WeakReference r = new WeakReference(new String(chars).intern());
... you should find that the weak reference is (eventually) broken. (It might take a couple of GC cycles though.)
…你应该发现弱引用(最终)被破坏了。(不过可能需要几个GC周期。)
1 - In theory, causing the class to be unloaded and garbage collected could get rid of the last reachable hard reference to that String literal. However, if that happened in this case, you'd be past the point at which you'd be able to observe the state of the WeakReference object. At least, in with your example code. Besides, unless you boot your JVM with a custom class loader, I don't think it would be possible to cause the unloading of the entrypoint class. It's not the kind of thing that is easy, or useful to do.
1 -理论上,导致类被卸载和垃圾收集可以消除对字符串字面量的最后可访问的硬引用。但是,如果在这种情况下发生这种情况,那么您就可以通过观察WeakReference对象的状态。至少,在示例代码中。此外,除非您使用自定义类装入器引导JVM,否则我认为不可能导致entrypoint类的卸载。这不是一件容易或有用的事情。
#2
1
It is becuase of string pooling.When you create string with new operator, it will get created in pool and available for normal garbage collection.But when you define string as literal, it will get created in string pool, and it wont get garbage collected with normal gc operation
这是因为字符串池。当您使用new操作符创建字符串时,它将在池中创建,并可用于正常的垃圾收集。但是,当您将字符串定义为文字时,它将在字符串池中创建,并且不会通过正常的gc操作收集垃圾
#3
-1
Static variables are Garbage Collected only when the class is unloaded. Therefore you can see that the value of the static variable is still printed even after you manually triggered garbage collection.
静态变量只有在类被卸载时才被收集。因此,您可以看到,即使在手动触发垃圾收集之后,静态变量的值仍然被打印出来。