Java中如何对字符串进行垃圾收集?

Java中如何对字符串进行垃圾收集?,java,string,memory-leaks,garbage,Java,String,Memory Leaks,Garbage,我正在读关于JVM中内存管理的书,如果一个对象不再引用它,它就会被垃圾收集。 比如说,我有一个程序 public test { public static void main(String[ ] args) { String name = "hello"; for (int i =0 ; i < 5; i++) { System.out.println(i); } } } 这里再次强调,hello的引用必须始终存在,并

我正在读关于JVM中内存管理的书,如果一个对象不再引用它,它就会被垃圾收集。 比如说,我有一个程序

public test {
  public static void main(String[ ] args) {
      String name = "hello";  
      for (int i =0 ; i < 5; i++) {
         System.out.println(i);
       }
   }
}
这里再次强调,
hello
的引用必须始终存在,并且不能被垃圾收集,因为
name2
使用它

那么这些
字符串
或任何
对象
什么时候会被垃圾收集,它们有引用,但已过时,即不再在代码中使用


我可以看到一种情况,减少数组会导致内存泄漏,因此将其引用设置为null是垃圾收集这些过时引用的好方法。

Java中的每个变量都有一个作用域:定义变量的代码段。在您的示例中,像
name
这样的局部变量的范围位于它所在的括号
{}
之间。因此,当线程到达
字符串name=“hello”时,将定义
name
变量声明,并将保持活动状态,直到
main
方法完成(因为此时变量所在的括号已关闭)


但字符串与其他变量不同。字符串是在内部缓存的,实际上可能还不能用于垃圾收集器。

从技术上讲,JVM永远不需要垃圾收集对象。实际上,它们通常在最后一次引用消失后的一段时间内返回,并释放内存

首先,要知道常数总是存在的。即使您为
name
指定了一个新值,系统仍然有一个与类一起存储的
“hello”
副本,它将在每次点击该初始值设定项语句时重用该副本

但是,不要混淆使用对象进行某种计算和永远保留对它的引用。在您的第二个示例中,虽然“hello”
实际上一直存在,但这只是因为它生活在常量池中
name2
没有任何形式的“保持”功能将其保留在内存中。对
substring
的调用将执行并完成,
name
上没有永久保持。(Oracle JVM中的实际实现共享底层的
char[]
,但这取决于实现。)

清除阵列是一种很好的做法,因为它们通常是长寿命的和可重用的。如果对整个数组进行垃圾收集,则它所持有的引用将被擦除(如果这些引用是最后一个引用,则其对象将被垃圾收集)

我可以看到一种情况,即减少阵列会导致内存泄漏 因此,将其引用设置为null是消除垃圾的好方法 收集那些过时的参考资料

字符串是引用类型,因此所有与垃圾收集有关的引用类型规则都适用于字符串。JVM也可能对字符串文本进行一些优化,但是如果您担心这些,那么您可能想得太多了

JVM何时收集未引用的对象

唯一重要的答案是:你不能说,也不必说,但如果说了,你就不知道什么时候会说。决不能围绕确定性垃圾收集编写Java代码。这是没有必要的,而且充满了丑陋

一般来说,如果您将引用变量(包括引用类型的数组或集合)限制在尽可能狭窄的范围内,那么您就不必担心内存泄漏了。长寿命引用类型将需要一些护理和喂养

“修剪”数组(通过将
null
分配给数组元素来取消对数组元素的引用)仅在数组表示您自己的内存管理系统的特殊情况下(例如,如果您正在创建自己的缓存或对象队列)才是必要的


因为JVM无法知道您的阵列正在“管理内存”,所以它无法收集阵列中仍被引用但已过期的未使用对象。如果数组代表您自己的内存管理系统,那么您应该将
null
分配给对象已过期的数组元素(例如,从队列中弹出;J.Bloch,Essential Java,第二版)。

Java的当前版本在
name2
中不保留对
name
的引用,在这种情况下,
name
可以自由收集。还有,你说的“精简数组”是什么意思?@LouisWasserman我想他说的是将未使用的条目置零。当你说“常量总是在附近”时,这是否意味着如果我有
公共最终整数计数=100
,那么
整数
对象是否永远保留?是的。事实上,即使您只有一个字段初始值设定项(
private Integer count=0;
),只要类本身在范围内,
Integer
对象就会一直存在。(实际上,在全计算机上的JVM中,
Integer
s for-128..127始终保持在附近以提高速度。)当谈到范围时,一旦对象的范围完成(使用{}),对它的引用是否丢失??一旦变量超出范围,它就不再存在。当引用变量超出范围时,其引用将立即丢失。如果该变量引用的对象未在应用程序中的任何其他位置引用,则它将自动成为“符合垃圾收集条件的对象”。在Visual Basic 5.0中,有必要小心地
null
out引用变量,以防止内存泄漏,但这在Java中是不必要的,被认为是不好的做法,尤其是当变量很快就超出范围时。假设您有一个引用类型数组。数组本身是引用类型。如果数组仅由应用程序中的单个变量引用,并且数组引用的对象不在其他任何位置引用。。。那么当参考变量b
String name = "hello"
  String name2 = name.substring(1,4)//"ell"