考虑以下情况:
String dude = "Harold";
//some stuff
dude = "Kumar";
一旦dude
被赋予其第二个值“Kumar”,就会出现一个与“Harold”分开的全新对象。我想知道的是,因为“哈罗德”显然没有用,它是立即收集垃圾还是在JVM认为合适的时候收集?
更新
仅仅因为dude
被设置为新值(对象)并不一定意味着已经消除了对旧对象的所有引用。如果另一个引用在“Harold”之后和“Kumar”之前调用dude
,它显然会保留“Harold”对象:
String dude = "Harold";
//some stuff
String interim = dude;
dude = "Kumar";
System.out.println("dude = " + dude);
System.out.println("interim = " + interim);
打印
dude = Kumar
interim = Harold
因此,有比我最初想象的更多的考虑因素,因此初始值不一定必须在更改后超出范围。
答案 0 :(得分:5)
不会立即对垃圾进行垃圾收集,并且不鼓励尝试强制进行垃圾收集(并且每次发布java时都会变得越来越困难)。
是的,分钟“Harold”不再可达(没有指针链通向它)它有资格进行垃圾收集并可能被收集(如果GC运行)。话虽如此,可以在const池中分配字符串,它位于perm gen中并且不是GC *(至少直到java 7)。有关实习字符串的更多信息:http://www.codeinstructions.com/2009/01/busting-javalangstringintern-myths.html
* - 不完全准确,即使它处于perm gen,const池仍然是GC。它很复杂。
答案 1 :(得分:2)
通常情况下,垃圾收集不会立即发生。此外,字符串是不可变的并且保存在一个全局表中(据我所知,大多数JVM都是这样)因此它可能永远不会被收集。
答案 2 :(得分:2)
这一个:“在JVM认为合适的某个时候”。 垃圾收集花费CPU,可能意味着暂停线程。 GC是一个非常复杂的东西,不断平衡CPU与内存的使用。
正如其他人所说,字符串更复杂,但我想你一般都想知道java对象。 我不认为关于String的所有这些问题都与你的问题非常相关,并使这个问题变得比它需要的复杂得多!
答案 3 :(得分:2)
因为“Harold”显然没有任何用处
你是如何得出这个结论的?只是通过查看您参考的单个班级?但是根据the Java Language Specification,在以下情况下重用字符串文字
因此,除非你确定上述所有情况都不正确,否则你可能不会指望它甚至有资格进行垃圾收集。
答案 4 :(得分:1)
让我们忘记,常数String
可能会有不同的处理方式。对象未立即进行垃圾回收的主要原因是可能存在其他引用。例如,如果您的“某些内容”包含类似
t = dude;
将新值分配给dude
时,无法访问该对象。要找出所有参考资料的成本相当高,因此只在必要时才进行。
答案 5 :(得分:1)
虽然几乎每个Java规范的实现都使用跟踪垃圾收集器,但我不相信规范要求使用跟踪GC来管理堆。
可以想象GC实现包含引用计数。在上述情况的这种变化中(为避免const池细节而设计):
String dude = new String("Harold");
//
dude = new String("Kumar");
dude
引用计数引用的原始对象变为零,可能立即被垃圾收集。
关键是 - 使用Java,没有保证,但通常你不必担心它。
答案 6 :(得分:0)
String
是immutable
。当您重新分配变量dude dude = "Kumar"
旧字符串对象超出范围时。
当垃圾收集器开始工作时,它收集了该对象。