Java在创建对象时速度慢吗?

10
在我的当前项目(OpenGL Voxel Engine)中,在生成模型时我遇到了一个严重的问题。我采用了非常面向对象的结构,这意味着即使是顶点的单个参数也是Object类型。因此,在大约5秒钟内为750个像素创建了大约75000个Object。Java分配新的Object是否真的这么慢,还是我在代码中错过了什么重大失误?

一个好的JVM在创建对象方面的速度可能比C++系统更快。只是在Java中使用了如此之多的对象(特别是当应用程序设计不良时)。 - Hot Licks
这也取决于对象的生命周期有多长,如果你正在创建一堆短暂存在的对象,垃圾回收器可能会介入,降低性能。我以前实现过对象池,在使用基本 Swing 图形的情况下,允许将移动对象的数量从 500 增加到 4500。 - MadProgrammer
没有太多的代码可以展示。只有一些构造函数和一个填充了对象的数组用于模型。 - th3falc0n
没有看到代码,我们无法提供更多帮助。如果您可以至少发布构造函数(以及它们调用的方法),这可能会解决问题。特别是如果有一些嵌套循环,这可能会影响性能。 - Reinstate Monica -- notmaynard
3
好的,我刚刚发现我在添加每个顶点时都重新生成了我的VBOs。问题已解决。 - th3falc0n
显示剩余5条评论
6个回答

7
非常重要的问题。一般来说,这取决于对象类定义和构造对象所需的工作量。
一些问题:
  1. 避免使用finalize方法
  2. 调整内存和GC以避免过度的GC活动
  3. 在构造函数期间避免大量工作
  4. 不要在对象构造期间使用同步调用
  5. 使用弱引用
这些问题解决了我的问题。
另请参阅http://oreilly.com/catalog/javapt/chapter/ch04.html 最后让我建议您使用(已弃用的)对象池模式或重用对象。
总之,一般来说,Java对象创建并不慢。

1
在这个问题上,我认为问题出在第三点:构建过程中有很多工作量。我只会改变最后一句话,即“一般来说,Java 在创建对象方面非常快速”。几个月前,我找到了一些基准测试来证明这一点,我应该再去找找它们。 - ThanksForAllTheFish
@Mardavi 如果你能够检索到基准测试数据,那将非常有趣。 - venergiac
1
开始:http://onlinevillage.blogspot.ch/2011/03/is-javascript-is-faster-than-c.html 另外,这也很有趣(没有显示结果,但它深入了解了Java性能监控):http://www.ibm.com/developerworks/library/j-5things8/ - ThanksForAllTheFish

5
当然不是。下面的代码会分配1000万个对象并将它们存储在一个数组中。在我的五年老笔记本电脑上,这个过程只需要1.4秒钟。
public class Test {
    public static void main(String[] args) {
        Object[] o = new Object[10_000_000];
        long start = System.nanoTime();
        for (int i = 0; i < o.length; i++) {
            o[i] = new Object();
        }
        long end = System.nanoTime();
        System.out.println(Arrays.hashCode(o));
        System.out.println(new BigDecimal(end - start).movePointLeft(9));
    }
}

尽管这个基准测试相当简单,它没有在计时器开始之前触发代码的即时编译,但是即使如此,它也能够发挥作用。


2

仅仅创建75,000个对象不应该需要5秒钟的时间。查看一下你的构造函数在做什么工作。除了创建对象之外,在这段时间内你还在做什么?你尝试过计时代码来确定延迟发生的位置吗?


1
正如我在问题命令中所说,我在我的引擎中找到了错误。 - th3falc0n

1

对象比原始类型更慢,而且它们会消耗更多的内存——因此可能你对它们过于追求了。没有看到更多细节很难说。

创建75000个对象不需要太长时间,可以尝试这样做:

List<Integer> numbers = new ArrayList<Integer>();
    for(int i = 0;i<75000;i++){
        numbers.add(i); // Note this will autobox creating an Integer object after the first 128
    }
    System.out.println(numbers.size());
}

http://www.tryjava8.com/app/snippets/52d070b1e4b004716da5cb4f

总共花费不到一秒钟的时间。

当我将数字增加到7,500,000时,最终需要花费一秒钟的时间...


1
谢谢这个有趣的网站,但我想我刚刚让服务器崩溃了 o.O - th3falc0n

1
Java中的new运算符与没有自动内存管理的语言中常见的方法相比非常快(例如,new运算符通常比C语言中的malloc命令更快,因为它不需要系统调用)。
虽然new运算符仍然可能成为瓶颈,但在您的情况下肯定不是问题。创建75000个对象应该比5秒钟快得多。

0

我在创建新对象时遇到了同样的问题。

我的构造函数中分配了一个单一的三维数组64x64x64,没有更多。FPS下降到原来的四分之一。

我通过重用旧对象并重置其状态来解决这个问题(顺便说一句,这种方法重新分配该数组而不会失去性能)。

如果我将分配数组的方法移动到单独的方法中,并在创建对象后调用它,则速度不会增加到可接受的值。

我创建的这个对象在主游戏循环中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接