5

在Java中,如果我有很多本地对象,如果我将它们定义为实例变量,它会运行得更快吗?例如,如果我的 func1() 被多次调用,比如在一个循环中,JVM 会在每次调用该函数时继续实例化和垃圾收集 list2 吗?相反,我是否应该重用相同的 list1 对象来防止垃圾收集和实例化开销?

class A {
   List list1 = new ArrayList();
   private void func1() {
      list1.clear();
      // add new objects list1

      List list2 = new ArrayList();
      // add new objects to list2
   }
}

优化器会足够聪明地跳过垃圾收集并自动重用对象吗?

4

5 回答 5

2

GC 优化不是决定LocalvsInstance变量的正确方法。如果一个变量需要被多个实例方法使用,那么使用实例变量是有意义的。

你是对的,局部变量的使用可能会增加 GC 活动。

于 2013-10-09T09:48:15.917 回答
1

在决定使用局部变量还是实例变量之前,您可能需要考虑各种用例。性能可能因用例而异。

一个很好的例子可以在Effective Java中找到:第 5 项- '避免创建不必要的对象'

于 2013-10-09T09:52:56.597 回答
1

还要考虑实例变量值的线程安全性。同一对象的两个线程需要对实例变量数据进行同步访问,但这里它总是一个新的局部变量数据对象。

于 2013-10-09T09:54:46.207 回答
1

如果 -并且仅当- 您已经证明由于创建对象而存在 GC 问题,您应该考虑将被证明创建成本高昂的对象池化。

为此,您不必重新发明任何轮子,您可以使用 Javolutions utils 来实现它,这种情况下使用FastList.newInstance()调用来实现 FastList:

List<Whatever> newOrReusedList = FastList.newInstance();

...以及相应的FastList.recycle(FastList)调用以使其可重用。(感谢@JIV,我忘了添加这一点。)

(但请注意,使用 javolutions Fast* 类可能会导致不同的性能:它们面向可预测的性能(实时系统)而不是速度,因此可能存在一些用例,当它们的执行速度比它们的 java.lnag 对应物慢时)

于 2013-10-09T09:58:03.303 回答
1

我用jdk1.6写了一个小测试程序,如下

结果:
* dostuff(创建本地)
594ms * dostuff2(使用实例)58ms

public class Test {

static long counter=0;
public static void main(String[] args) {
    long t1  = System.nanoTime();
    Test test = new Test();
    for (int i=0;i<1000000000;i++) {
        test.doStuff();//or dostuff2
    }
    long t2  = System.nanoTime();
    System.err.println((t2-t1)/1000000);
    System.err.println(counter); // to check it wasnt optimised away
}

private void doStuff() {
    List l = new ArrayList();
    if (l!=null) {
        counter++;
    }
}

List l2 = new ArrayList();
private void doStuff2() {
    if (l2!=null) {
        counter++;
    }
}
}

结果,正如人们所期望的那样,该实例似乎比使用 local 更快。

但是,至少在我的 PC 上,您似乎每十亿件物品节省了大约 0.5 秒,所以您需要真正需要性能增益来证明它的合理性

于 2013-10-09T10:05:19.587 回答