将创建多少个对象以及可用于垃圾回收的对象数量?

时间:2016-11-08 05:50:34

标签: java string garbage-collection

String str = "test";

str = str + "test2";
str = str + "test3";
str = str + "test4";
str = str + "test5";

将从上面的代码创建多少个对象以及有多少对象可用于垃圾回收?

有人可以解释一下吗?

2 个答案:

答案 0 :(得分:0)

关于字符串操作,JavaC非常奇怪。例如,为什么当你执行“String + = otherString”时他们不使用String.concat?

相反,Java为每一行结束时创建一个StringBuilder(或StringBuffer,具体取决于Java版本);你已经连接了字符串。

我将您的代码放在测试程序(TCTestWin)中并从命令行调用:

javap -c TCTestWin.class

结果如下:

   0: ldc           #15                 // String test
   2: astore_1
   3: new           #17                 // class java/lang/StringBuilder
   6: dup
   7: aload_1
   8: invokestatic  #19                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
  11: invokespecial #25                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  14: ldc           #28                 // String test2
  16: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  19: invokevirtual #34                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  22: astore_1
  23: new           #17                 // class java/lang/StringBuilder
  26: dup
  27: aload_1
  28: invokestatic  #19                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
  31: invokespecial #25                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  34: ldc           #38                 // String test3
  36: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  39: invokevirtual #34                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  42: astore_1
  43: new           #17                 // class java/lang/StringBuilder
  46: dup
  47: aload_1
  48: invokestatic  #19                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
  51: invokespecial #25                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  54: ldc           #40                 // String test4
  56: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  59: invokevirtual #34                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  62: astore_1
  63: new           #17                 // class java/lang/StringBuilder
  66: dup
  67: aload_1
  68: invokestatic  #19                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
  71: invokespecial #25                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  74: ldc           #42                 // String test5
  76: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  79: invokevirtual #34                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  82: astore_1
  83: return

如您所见,对于每一行,JavaC创建一个StringBuilder,追加String,然后继续。

这样的代码,特别是在循环中使用时,会抢占垃圾收集器。

有三种更好的方法:

  1. 改为使用concat:

    String str = "test";
    str = str.concat("test2");
    str = str.concat("test3");
    str = str.concat("test4");
    str = str.concat("test5");
    
  2. 使用单行连接,这将创建一个StringBuilder。记住每个;将创建另一个StringBuilder。请注意,在下面的常量字符串的串联中,Java编译器将创建一个String。但是,如果添加一个或多个String变量,则将创建StringBuilder。

    String str = "test" + "test2" + "test3" + "test4" + "test5";
    
  3. 自己创建一个StringBuilder,进行连接,然后重新使用 StringBuilder。这具有最佳性能,特别是在循环中执行时。

    StringBuilder sb = new StringBuilder(512);
    for (int i = 0; i < 10000; i++)
    {
       sb.setLength(0);
       sb.append("test");
       sb.append("test2");
       sb.append("test3");
       sb.append("test4");
       sb.append("test5");
       sb.append(i);
       String s = sb.toString();
    }
    
  4. 因此,从上面的代码中,将创建4个不同的StringBuilder。在最终的String之后,将收集所有StringBuilders。

答案 1 :(得分:0)

  

将创建多少个对象

在运行时,4,即str的四个计算值,不包括来自常量池的初始值。

  

有多少个对象可用于垃圾回收?

在此代码的末尾,但在str超出范围之前,有三个,即str的三个中间值。

请注意,我正在计算Strings。每个String都会有一个关联的char[],这是另一个对象。

但是,如果周围的代码是这样的,JVM可以确定str不能在这些代码行之间改变,那么它可以分别为1和0。