我有一个在(大)图上运行的 Java 程序。因此,它使用了大量的堆空间(~50GB,约占主机物理内存的 25%)。有一次,程序(重复地)从图中选择一个节点并用它做一些计算。对于某些节点,此计算花费的时间比预期的要长得多(30-60 分钟,而不是预期的几秒钟)。为了分析这些操作以找出花费如此多时间的原因,我创建了一个测试程序,该程序仅创建大图的一小部分,然后在其中一个计算时间很长的节点上运行相同的操作原来的程序。因此,与原始程序相比,测试程序显然只使用了非常少的堆空间。
原来在原程序中需要 48 分钟的操作在测试程序中可以在 9 秒内完成。这真的让我很困惑。第一个想法可能是较大的程序在垃圾收集上花费了大量时间。所以我打开了虚拟机垃圾收集器的详细模式。据此,48 分钟内没有进行全量垃圾回收,新生代仅进行了约 20 次回收,每次回收不到 1 秒。
所以我的问题是还有什么可以解释如此巨大的时间差异?我不太了解Java内部如何组织堆。对于具有大量 Activity 对象的大型堆,是否需要花费更长的时间?会不会是因为在堆中找到合适的位置需要更长的时间,所以在这种情况下对象分配需要更长的时间?或者 VM 是否对堆进行任何可能花费大量时间的内部重组(显然除了垃圾收集之外)。
我正在使用 Oracle JDK 1.7,如果这很重要的话。
最佳答案
虽然更大的内存可能意味着更大的问题,但我认为没有什么(除了您排除的 GC)可以将 9 秒延长到 48 分钟(320 倍)。
大堆可能会导致看似更糟糕的空间局部性,但我认为这无关紧要。我不同意蒂姆的回答 w.r.t. “必须为所有内容保留缓存”。
还有 TLB这是一个用于虚拟地址转换的缓存,这可能会导致非常大的内存出现一些问题。但同样,不是因子 320。
我认为 JVM 中没有任何东西会导致此类问题。
我能想到的唯一原因是你有一些被使用的交换空间——尽管你有足够的物理内存。即使是轻微的交换也可能导致巨大的减速。确保它已关闭(并可能检查 swappiness )。
关于大堆的 Java 速度较慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21671725/