5

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

ByteBuffer当没有序列化问题时(例如,如果我将它与巨大的byte[]. 还是垃圾收集等的变幻莫测使这个问题无法回答?我知道“测量它”是一个常见的答案,但恐怕我不会设置一个有代表性的测试,因为我还不够了解 Java 中的原生内存是如何工作的。

4

3 回答 3

4

直接内存在执行 IO 时速度更快,因为它避免了数据的一份副本。但是,对于 95% 的应用程序,您不会注意到差异。

您可以将数据存储在直接内存中,但它不会比存储数据 POJO 快。(或安全、可读或可维护)如果您担心 GC,请尝试提前创建对象(必须是可变的)并重用它们而不丢弃它们。如果你不丢弃你的物品,就没有什么可收集的。


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

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

还是垃圾收集等的变幻莫测使这个问题无法回答?

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

顺便说一句:如果你尽量减少你丢弃的对象的数量并增加你的伊甸园大小,你可以防止长时间(例如一整天)发生即使很小的收集。

于 2011-05-02T23:00:12.783 回答
2

BigMemory 的重点不是本机内存更快,而是减少垃圾收集器必须通过跟踪内存引用并清理它的工作的开销。随着堆大小的增加,您的 GC 间隔和 CPU 承诺也会增加。视情况而定,这可能会产生一种“玻璃天花板”,Java 堆变得如此之大,以至于 GC 变成了一只猪,每次 GC 启动时都会占用大量的处理器资源。此外,许多 GC 算法需要某种程度的锁定意味着在 GC 引用跟踪算法的那部分完成之前没有人可以做任何事情,尽管许多 JVM 在处理这方面已经做得更好。在我工作的地方,使用我们的应用服务器和 JVM,我们发现“玻璃天花板”大约是 1.5 GB。如果我们尝试将堆配置得比这个大,GC 例程开始占用超过 50% 的总 CPU 时间,所以这是一个非常实际的成本。我们通过 JVM 供应商提供的各种形式的 GC 分析确定了这一点。

另一方面,BigMemory 采用更手动的内存管理方法。它减少了开销,并且让我们回到了必须自己进行内存清理的工作,就像我们在 C 中所做的那样,尽管采用类似于 HashMap 的更简单的方法。这基本上消除了对传统垃圾收集例程的需求,因此,我们消除了这种开销。我相信 Terracotta 人通过 ByteBuffer 使用本机内存,因为这是从 Java 垃圾收集器中脱离出来的一种简单方法。

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

于 2011-05-03T03:29:45.503 回答
1

如果可以绕过序列化问题,我对本机内存可以完成的工作很感兴趣。

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

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

  • 只有在您知道需要时才走这条路。(您将把您的应用程序与特定的实现技术联系起来。)

  • 如果所涉及的数据尚未作为缓存进行管理,请准备好对应用程序进行一些侵入性更改。

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

  • 如果您的数据结构很复杂,预计运行时开销和调优工作会相应增加。

于 2011-05-03T02:19:39.077 回答