在循环中使用字符串而不是StringBuilder会有内存损失吗?

时间:2014-12-27 14:43:52

标签: java performance

我有这个测试循环:

String str_1;
Object an_object_var = new Object();

long startTime = System.nanoTime();

for(int i = 0; i < 100000; i++)
{
    an_object_var=(Object)i;
    str_1 = an_object_var.toString();            
}

long endTime = System.nanoTime();

long timig = endTime - startTime;
System.out.println(timig);

StringBuilder sb = new StringBuilder();
an_object_var = new Object();

System.out.println(new Date());

startTime = System.nanoTime();

for(int i = 0; i < 100000; i++)
{
    an_object_var=(Object)i;
    sb.delete(0, sb.length());
    sb.insert(0, an_object_var);
}

endTime = System.nanoTime();

timig = endTime - startTime;
System.out.println(timig);

我没有连接字符串,只是做了一些拆箱。第一个循环比第二个循环快得多(15441625 vs 26869129纳秒。我在NetBeans上运行它们)。但是,只要字符串是不可变的,我就会在第一个循环中在内存中创建100000个变量(直到下一个Garbage Colector传递)。 在第一个循环中是否存在内存惩罚,而在第二个循环中没有发生?

2 个答案:

答案 0 :(得分:2)

是的,区别在于编译器可以从第一个示例中删除更多代码,因为它没有做任何有用的事情。第二个循环更难以优化为零。

你遇到的另一个问题是第一个循环触发了整个方法的优化,在这种情况下,JIT没有关于第二个循环的信息,所以它也不能对它进行优化。我建议你把两个测试放在他们自己的方法中然后运行多次。确保测试每个运行至少2秒。

BTW如果您使用

sb.setLength(0);
sb.append(i);

而不是

an_object_var=(Object)i;
sb.delete(0, sb.length());
sb.insert(0, an_object_var);

这样可以避免造成任何垃圾。

答案 1 :(得分:1)

因为垃圾收集器不允许内存泄漏,所以没有内存惩罚,因为这句话:

str_1 = an_object_var.toString(); 

将导致GC在更改引用之前释放旧的字符串对象 编辑:有人说你不能声称gc会这样做,即使如此,你可以这样确定自己:

for(long i = 0; i < 1000000000000; i++)
{
   an_object_var=(Object)i;
   str_1 = an_object_var.toString();            
}

我怀疑记忆能否存活下来!