Java Native Memory比堆更快吗?

时间:2011-05-02 22:51:14

标签: java memory garbage-collection bytebuffer terracotta

我正在探索帮助我的内存密集型应用程序的选项,并且在这样做时我遇到了Terracotta的BigMemory。从我收集的内容来看,它们利用了非垃圾收集的堆外“本机内存”,显然由于序列化/反序列化问题,这比堆存储慢大约10倍。在阅读BigMemory之前,我从未听说过正常JNI之外的“本机记忆”。尽管BigMemory是一个值得进一步考虑的有趣选项,但如果可以绕过序列化问题,我对本机内存可以实现的目标很感兴趣。

当没有序列化问题时(例如,如果我将它与巨大的ByteBuffer进行比较),Java本机内存是否比传统堆内存更快(我认为这需要byte[]个对象?)?或者做垃圾收集的变幻莫测等让这个问题无法回答?我知道“测量它”是一个常见的答案,但我担心我不会设置一个代表性测试,因为我还不了解本机内存在Java中是如何工作的。

3 个答案:

答案 0 :(得分:4)

执行IO时,直接内存更快,因为它可以避免一个数据副本。但是,对于95%的申请,您不会注意到差异。

您可以将数据存储在直接内存中,但是它不会比存储数据POJO快。 (或安全,可读或可维护)如果您担心GC,请提前尝试创建对象(必须是可变的)并重复使用它们而不丢弃它们。如果您不丢弃对象,则无需收集任何内容。


  

当没有序列化问题时,Java本机内存是否比传统堆内存更快(我认为这需要ByteBuffer对象?)(例如,如果我将它与一个巨大的字节[]进行比较)?

如果使用像int这样的非字节,直接内存可能比使用字节[]更快,因为它可以读取/写入整个四个字节而无需将数据转换为字节。 但是它比使用POJO要慢,因为它必须检查每次访问。

  

或者做垃圾收集的变幻莫测等让这个问题无法回答?

速度与GC无关。 GC仅在创建或丢弃对象时很重要。

顺便说一句:如果你减少丢弃的物体数量并增加你的伊甸园尺寸,你可以防止长时间发生轻微的收集,例如整整一天。

答案 1 :(得分:2)

BigMemory的观点并不是本机内存更快,而是减少垃圾收集器不得不通过跟踪内存引用并清理内存的开销。随着堆大小的增加,GC间隔和CPU承诺也会增加。根据具体情况,这会产生一种“玻璃天花板”,其中Java堆变得如此之大以至于GC变成了猪,每次GC启动时都会占用大量的处理器功率。此外,许多GC算法需要某种程度的锁定意味着在GC参考跟踪算法的这一部分完成之前,任何人都无法做任何事情,尽管许多JVM在处理这个问题时已经做得更好。在我工作的地方,通过我们的app服务器和JVM,我们发现“玻璃天花板”大约是1.5 GB。如果我们尝试将堆配置为大于此值,则GC例程开始占用总CPU时间的50%以上,因此这是非常实际的成本。我们通过JVM供应商提供的各种形式的GC分析确定了这一点。

另一方面,BigMemory采用更加手动的内存管理方法。正如我们在C中所做的那样,它减少了开销和排序,使我们不得不进行自己的内存清理,尽管它采用类似于HashMap的更简单的方法。这基本上消除了对传统垃圾收集例程的需要,因此,我们消除了这种开销。我相信Terracotta人通过ByteBuffer使用本机内存,因为它是一种从Java垃圾收集器下面出来的简单方法。

以下白皮书介绍了他们如何构建BigMemory以及GC开销的一些背景信息:http://www.terracotta.org/resources/whitepapers/bigmemory-whitepaper

答案 2 :(得分:1)

  

如果可以绕过序列化问题,我对本机内存可以实现的目标很感兴趣。

我认为你的问题是基于错误的假设。 AFAIK,不可能绕过他们在这里谈论的序列化问题。您唯一能做的就是简化放入BigMemory的对象,并使用自定义序列化/反序列化代码来减少开销。

虽然基准测试可能会让您大致了解开销,但实际开销将非常适合应用程序。我的建议是:

  • 如果您知道自己需要,只能走这条路。 (您将把应用程序与特定的实现技术联系起来。)

  • 如果尚未使用缓存管理相关数据,请准备好对应用程序进行一些侵入式更改。

  • 准备花一些时间(重新)调整缓存代码,以便通过BigMemory获得良好的性能。

  • 如果您的数据结构很复杂,那么预计会有相应较大的运行时开销和调优工作量。