【问题标题】:Java slower with big heapJava 堆大时速度较慢
【发布时间】: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


【解决方案1】:

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

一个大堆使看似更糟糕的空间局部性成为可能,但我认为这并不重要。我不同意蒂姆的回答 w.r.t. “必须为所有内容保留缓存”。

还有TLB,它是一个用于虚拟地址转换的缓存,这可能会导致一些非常大的内存问题。但同样,不是因素 320。

我认为 JVM 中没有任何东西会导致此类问题。

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

【讨论】:

  • 据我所知,没有发生交换。根据您的回答,我只能推断问题出在我的代码中。我将不得不进一步调查。谢谢!
  • 你找到问题了吗?
【解决方案2】:

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

尽管您描述的症状和差异很大,但我认为缓存一致性这样简单的事情并没有有很大的不同。

我能给你的最好建议是尝试在运行缓慢和快速运行时针对它运行分析器并比较差异。

您需要可靠的数字和时间安排。 “在这种环境下做 X 花了 Y 时间”。从那你可以开始缩小范围。

【讨论】:

    猜你喜欢
    • 2015-09-22
    • 2017-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 2021-12-01
    • 2010-12-08
    • 2019-03-02
    相关资源
    最近更新 更多