【发布时间】:2014-03-07 11:03:25
【问题描述】:
我有一个在(大)图上运行的 Java 程序。因此,它使用了大量的堆空间(~50GB,大约是主机物理内存的 25%)。在某一时刻,程序(重复地)从图中选择一个节点并对其进行一些计算。对于某些节点,此计算花费的时间比预期的要长得多(30-60 分钟,而不是预期的几秒钟)。为了分析这些操作以找出花费这么多时间的原因,我创建了一个测试程序,它只创建大图的一小部分,然后在一个需要很长时间才能计算的节点上运行相同的操作原始程序。因此,与原始程序相比,测试程序显然只使用了非常少的堆空间。
原来在原程序中需要 48 分钟的操作,在测试程序中可以在 9 秒内完成。这真的让我很困惑。第一个想法可能是较大的程序在垃圾收集上花费了大量时间。所以我打开了VM的垃圾收集器的详细模式。据此,在这 48 分钟内没有进行完整的垃圾回收,年轻代仅进行了大约 20 次回收,每次不到 1 秒。
所以我的问题是,还有什么可以解释时间上如此巨大的差异?我不太了解 Java 如何在内部组织堆。对于具有大量活动对象的大型堆,是否需要花费更长的时间?是不是在这种情况下对象分配需要更长的时间,因为在堆中找到合适的位置需要更长的时间?或者虚拟机是否对可能需要大量时间的堆进行任何内部重组(显然,除了垃圾收集)。
我使用的是 Oracle JDK 1.7,如果这很重要的话。
【问题讨论】:
-
不知道你的程序做了什么样的操作,这是无法回答的。
-
测试和主程序与可分配堆的数量有何不同?他们是否对其他类型的数据进行操作?测试应用程序使用多少堆,如果只使用少量堆,则有一个使用短指针的性能选项(但这绝不可以解释您的性能差异)
-
你应该使用一个好的分析器(例如YourKit)来分析缓慢的原因,我很难相信这里的任何人都能猜出问题的根源。
-
我正在测试程序中使用分析器。分析实际程序不是一个好的选择,因为它需要太长时间。 (即使没有分析器,创建大数据结构也需要数天时间。)我主要希望了解 VM 是否可以做除了垃圾收集之外的任何可能占用时间的事情。根据迄今为止的答案,情况似乎并非如此。
-
同时我已经确定了问题的根源。它与堆大小无关。这证实了下面接受的答案。
标签: java performance heap-memory