Java堆越慢越慢

我有一个在(大)图上运行的Java程序。 因此,它使用了大量的堆空间(~50GB,约占主机上物理内存的25%)。 有一次,程序(重复)从图中选择一个节点并用它进行一些计算。 对于某些节点,此计算需要比预期更长的时间(30-60分钟,而不是预期的几秒钟)。 为了分析这些操作以找出需要花费大量时间的内容,我创建了一个测试程序,它只创建大图的一小部分,然后在其中一个节点上运行相同的操作原计划。 因此,与原始程序相比,测试程序显然只使用非常少的堆空间。

事实certificate,在原始程序中花费48分钟的操作可以在测试程序中在9秒内完成。 这真让我困惑。 第一个想法可能是较大的程序花了很多时间在垃圾收集上。 所以我打开了VM垃圾收集器的详细模式。 据此,在48分钟内没有完整的垃圾收集,年轻一代只有大约20个收集,每个收集不到1秒。

所以我的问题是还有什么可以解释时间的巨大差异? 我不太了解Java如何在内部组织堆。 对于具有大量活动对象的大型堆,是否需要更长的时间? 可能是在这样的设置中对象分配需要更长的时间,因为在堆中找到足够的位置需要更长的时间吗? 或者VM是否会对堆进行任何内部重组,这可能需要花费很多时间(显然除了垃圾收集之外)。

我正在使用Oracle JDK 1.7,如果这非常重要的话。

虽然更大的内存可能意味着更大的问题,但我会说没有什么(除了你排除的GC)什么可以延长9秒到48分钟(因素320)。

大堆使得看似更糟糕的空间局部性成为可能,但我认为这并不重要。 我不同意蒂姆的回答,“ 必须为所有事情留下缓存 ”。

TLB也是虚拟地址转换的缓存,可能会导致内存非常大的问题。 但同样,不是因素320。

我不认为JVM中有任何可能导致此类问题的内容。

我可以想象的唯一原因是你有一些交换空间被使用 – 尽管你有足够的物理内存。 即使轻微的交换也可能导致大幅放缓。 确保它关闭(并可能检查swappiness )。

即使事物在内存中,您也可以在现代CPU上进行多级缓存数据。 每次离开缓存以获取数据时,速度都会变慢。 拥有50GB的ram可能意味着它必须为所有内容留下缓存。

你描述的症状和差异虽然很大,但我没有看到像缓存一致性这样简单的东西这些差异很大。

我可以给你的最好的建议是尝试运行一个分析器,当它运行缓慢和运行速度很快并比较差异时。

你需要扎实的数字和时间。 “在这个环境中做X花了Y时间”。 从那以后你可以开始缩小范围。