2

看这段代码:

MessageParser parser = new MessageParser();
for (int i = 0; i < 10000; i++) {
    parser.parse(plainMessage, user);
}

出于某种原因,它比运行更慢(大约 100 毫秒)

for (int i = 0; i < 10000; i++) {
    MessageParser parser = new MessageParser();
    parser.parse(plainMessage, user);
}

任何想法为什么?测试重复了很多次,所以它不仅仅是随机的。创建一个对象 10000 倍怎么会比创建一次快?

4

4 回答 4

10

因为 Java 具有“分代垃圾收集”,并且可以快速识别(在循环中)它没有重用相同的对象/内存空间,所以 GC 成本几乎为零。另一方面,您的长寿命对象将在苗圃一代中幸存下来,并且必须移出到主要一代。

总而言之,如果不进行适当的测试来衡量性能,您就无法真正假设性能。

于 2009-09-27T19:18:42.567 回答
0

在后续调用解析器时可能有一些逻辑来清理内部状态。

GC 是否在您的基准测试期间运行?实例化一个新对象相当便宜,如果您不计算在较快的情况下处理您创建的所有对象的时间,这不是一个公平的比较。

于 2009-09-27T19:18:02.247 回答
0

我不知道它是做什么的MessageParser,也不知道它来自哪里。它可能在内部“泄漏”。另一种可能性是对象离解析期间创建的数据越来越远。这意味着您可能会错过 TLA。此外,如果MessageParser保持内部状态并进入终身代,那么注意到它引用新数据的 GC 机制可能是一个问题(“卡片评分”是一个浮现在脑海中的行话)。

于 2009-09-27T19:22:26.460 回答
0

如果您在限制范围的同时对第一个示例进行基准测试会发生什么parser,即

{
    MessageParser parser = new MessageParser();
    for (int i = 0; i < 10000; i++) {
        parser.parse(plainMessage, user);
    }
}
// `parser` no longer visible

我希望这是最快的,因为只需要创建一个对象,并且 VM 仍然知道parser可以在循环后立即 gc'd。

于 2009-09-27T21:35:04.687 回答