77

Does anyone have experience with using very large heaps, 12 GB or higher in Java?

  • Does the GC make the program unusable?
  • What GC params do you use?
  • Which JVM, Sun or BEA would be better suited for this?
  • Which platform, Linux or Windows, performs better under such conditions?
  • In the case of Windows is there any performance difference to be had between 64 bit Vista and XP under such high memory loads?
4

14 回答 14

75

如果您的应用程序不是交互式的,并且 GC 暂停对您来说不是问题,那么 64 位 Java 处理非常大的堆(即使是数百 GB)也不应该有任何问题。我们也没有注意到 Windows 或 Linux 上的任何稳定性问题。

然而,当你需要保持低 GC 暂停时,事情会变得非常糟糕:

  1. 忘记默认的吞吐量,即停止世界的 GC。对于中等堆 (< ~30 GB),它将暂停您的应用程序数十秒,对于大型堆 (> ~30 GB),它将暂停几分钟。购买更快的 DIMM 也无济于事。

  2. 最好的选择可能是 CMS 收集器,由 -XX:+UseConcMarkSweepGC 启用。CMS 垃圾收集器仅在初始标记阶段和重新标记阶段停止应用程序。对于像 < 4 GB 这样的非常小的堆,这通常不是问题,但是对于创建大量垃圾和大堆的应用程序,重新标记阶段可能需要相当长的时间 - 通常比完全停止世界要短得多,但对于非常大的堆来说仍然是一个问题。

  3. 当 CMS 垃圾收集器在年老代填满之前不足以完成操作时,它会退回到标准的 stop-the-world GC。对于大小为 16 GB 的堆,预计会有大约 30 秒或更长时间的停顿。您可以尽量避免这种情况,使您的应用程序的长期垃圾产生率尽可能低。请注意,运行应用程序的核心数量越多,问题就越大,因为 CMS 只使用一个核心。显然,要注意不能保证 CMS 不会退回到 STW 收集器。当它发生时,它通常发生在峰值负载时,你的应用程序会死掉几秒钟。您可能不想为此类配置签署 SLA。

  4. 嗯,有新的 G1 东西。它在理论上旨在避免 CMS 的问题,但我们已经尝试过并观察到:

    • 它的吞吐量比CMS差。
    • 理论上它应该首先避免收集流行的内存块,但是它很快就会达到几乎所有块都是“流行”的状态,并且它所基于的假设只是停止工作。
    • 最后,G1 的 stop-the-world 后备方案仍然存在;询问甲骨文,该代码应该何时运行。如果他们说“从不”,问他们,为什么代码在那里。所以恕我直言,G1 并没有真正解决 Java 的巨大堆问题,它只会让它(可以说)更小一些。
  5. 如果您有钱购买具有大内存的大型服务器,那么您可能也有钱购买一种好的商业硬件加速、无停顿 GC 技术,比如 Azul 提供的技术。我们有一台具有 384 GB RAM 的服务器,它运行良好 - 没有停顿,GC 中有 0 行停止世界的代码。

  6. 用 C++ 编写需要大量内存的应用程序的该死部分,就像 LinkedIn 对社交图处理所做的那样。你仍然不会通过这样做来避免所有问题(例如堆碎片),但保持低暂停肯定会更容易。

于 2011-06-14T08:07:48.127 回答
17

我是 Azul Systems 的 CEO,所以我对这个话题的看法显然有偏见!:) 话虽如此...

Azul 的 CTO Gil Tene 很好地概述了与垃圾收集相关的问题,并在他的理解 Java 垃圾收集和您可以做什么演示文稿中回顾了各种解决方案,本文中还有其他详细信息:http:// www.infoq.com/articles/azul_gc_in_detail

我们的 Zing JVM 中的 Azul 的 C4 垃圾收集器既是并行的又是并发的,并且对新老代使用相同的 GC 机制,在两种情况下同时工作和压缩。最重要的是,C4 没有停止世界的退路。所有压缩都与正在运行的应用程序同时执行。我们有客户运行非常大(数百 GB),更糟糕的情况下 GC 暂停时间小于 10 毫秒,并且取决于应用程序,通常时间小于 1-2 毫秒。

CMS 和 G1 的问题在于,Java 堆内存在某些时候必须被压缩,并且这两个垃圾收集器都会停止世界/STW(即暂停应用程序)来执行压缩。因此,尽管 CMS 和 G1 可以推出 STW 暂停,但它们并不能消除它们。然而,Azul 的 C4 确实完全消除了 STW 暂停,这就是 Zing 即使对于巨大的堆大小也有如此低的 GC 暂停的原因。

于 2012-02-15T20:25:47.747 回答
14

We have an application that we allocate 12-16 Gb for but it really only reaches 8-10 during normal operation. We use the Sun JVM (tried IBMs and it was a bit of a disaster but that just might have been ignorance on our part...I have friends that swear by it--that work at IBM). As long as you give your app breathing room, the JVM can handle large heap sizes with not too much GC. Plenty of 'extra' memory is key.
Linux is almost always more stable than Windows and when it is not stable it is a hell of a lot easier to figure out why. Solaris is rock solid as well and you get DTrace too :) With these kind of loads, why on earth would you be using Vista or XP? You are just asking for trouble. We don't do anything fancy with the GC params. We do set the minimum allocation to be equal to the maximum so it is not constantly trying to resize but that is it.

于 2008-10-18T01:56:59.337 回答
9

我分别使用 Sun 1.6 JVM 的 64 位版本(显然)在 Linux 和 Solaris 下的两个不同应用程序上使用了超过 60 GB 的堆大小。

我从来没有遇到过基于 Linux 的应用程序的垃圾收集问题,除非在堆大小限制附近推高。为了避免该场景固有的抖动问题(花费太多时间进行垃圾收集),我简单地优化了整个程序的内存使用量,使峰值使用量比 64 GB 堆大小限制低 5-10%。

然而,在 Solaris 下运行不同的应用程序时,我遇到了严重的垃圾收集问题,因此需要进行大量调整。这主要包括三个步骤:

  1. 通过 -XX:+UseParallelGC -XX:+UseParallelOldGC JVM 选项启用/强制使用并行垃圾收集器,以及通过 -XX:ParallelGCThreads 选项控制使用的 GC 线程数。有关详细信息,请参阅“ Java SE 6 HotSpot 虚拟机垃圾收集调整”。

  2. 在不再需要局部变量后,将它们广泛且看似荒谬的设置为“null”。其中大多数是超出范围后应该有资格进行垃圾收集的变量,并且它们不是内存泄漏情况,因为没有复制引用。然而,出于某种原因,这种用于帮助垃圾收集的“手持”策略对于所讨论的 Solaris 平台下的该应用程序来说是莫名其妙的必要性。

  3. 在大量临时对象分配之后,在关键代码部分中选择性地使用 System.gc() 方法调用。我知道反对使用这些调用的标准警告,以及它们通常应该是不必要的论点,但我发现它们对于在运行这个内存密集型应用程序时驯服垃圾收集至关重要。

上述三个步骤使得在大约 60 GB 的堆使用量下保持该应用程序的可控性和高效运行成为可能,而不是失控到 128 GB 的堆大小限制。尤其是并行垃圾收集器非常有用,因为当有很多对象时,主要垃圾收集周期是昂贵的,即主要垃圾收集所需的时间是堆中对象数量的函数。

我无法评论这种规模的其他特定于平台的问题,我也没有使用过非 Sun (Oracle) JVM。

于 2010-12-02T02:21:00.287 回答
8

对于像 Sun 的 Hotspot 这样体面的 JVM 实现,12Gb 应该没有问题。我建议您在使用 SUN VM 时使用并发标记和扫描收集器 (-XX:+UseConcMarkSweepGC)。如果在 GC 期间所有线程都停止,您可能会面临漫长的“停止世界”阶段。

操作系统不应该对 GC 性能产生很大影响。

您当然需要 64 位操作系统和具有足够物理 RAM 的机器。

于 2008-10-18T20:08:56.523 回答
7

I recommend also considering taking a heap dump and see where memory usage can be improved in your app and analyzing the dump in something such as Eclipse's MAT . There are a few articles on the MAT page on getting started in looking for memory leaks. You can use jmap to obtain the dump with something such as ...

jmap -heap:format=b pid
于 2008-10-18T02:09:56.470 回答
2

如上所述,如果您有一个非交互式程序,默认(压缩)垃圾收集器 (GC) 应该可以正常工作。如果您有一个交互式程序,并且您 (1) 分配内存的速度不会超过 GC 可以跟上的速度,并且 (2) 不要创建太大(相对于总数)的临时对象(或对象集合)最大 JVM 内存)供 GC 解决,那么 CMS 适合您。

如果您有一个交互式程序,而 GC 没有足够的喘息空间,您就会遇到麻烦。不管你有多少内存都是如此,但你拥有的内存越多,情况就越糟糕。那是因为当你的内存太少时,CMS 将耗尽内存,而压缩 GC(包括 G1)将暂停所有内容,直到所有内存都被检查为垃圾。您拥有的内存越多,这种停止世界的暂停就越大。相信我,您不希望您的 servlet 暂停超过一分钟。我写了一个关于 G1 中这些暂停的详细 StackOverflow 答案。

从那以后,我的公司改用 Azul Zing。它仍然无法处理您的应用程序确实需要比您拥有的更多内存的情况,但直到那一刻它运行得像梦一样。

但是,当然,Zing 不是免费的,它的特殊酱汁是专利的。如果您的时间远多于金钱,请尝试重写您的应用程序以使用 JVM 集群。

Oracle 正在为数 GB 堆开发高性能 GC。但是,截至今天,这不是一个选择。

于 2014-05-01T23:00:04.297 回答
1

几年前,我比较了 JRockit 和 Sun JVM 的 12G 堆。JRockit 获胜,Linux 巨页支持使我们的测试运行速度提高了 20%。YMMV 作为我们的测试非常占用处理器/内存,并且主要是单线程的。

于 2009-05-14T16:22:25.387 回答
1

If you switch to 64-bit you will use more memory. Pointers become 8 bytes instead of 4. If you are creating lots of objects this can be noticeable seeing as every object is a reference (pointer).

I have recently allocated 15GB of memory in Java using the Sun 1.6 JVM with no problems. Though it is all only allocated once. Not much more memory is allocated or released after the initial amount. This was on a Linux but I imagine the Sun JVM will work just as well on 64-bit Windows.

于 2008-10-18T02:57:05.983 回答
1

这是来自 Java 冠军之一的关于 gc 的文章——http: //kirk.blog-city.com/is_your_concurrent_collector_failing_you.htm

Kirk,作者写道“把你的 GC 日志发给我

我目前有兴趣研究 Sun JVM 生成的 GC 日志。由于这些日志不包含业务相关信息,因此应该可以减轻对保护专有信息的担忧。我只要求您在日志中提及操作系统、JRE 的完整版本信息以及您设置的任何与堆/gc 相关的命令行开关。我还想知道您是否正在运行 Grails/Groovy、JRuby、Scala 或 Java 以外的其他东西或与 Java 一起运行的东西。最好的设置是-Xloggc:。请注意,此日志在达到您的操作系统大小限制时不会翻转。如果我发现任何有趣的东西,我很乐意给你一个非常快速的概要作为回报。"

于 2008-10-19T01:50:14.773 回答
1

您应该尝试对您的应用运行 visualgc。它是一个堆可视化工具,是 jvmstat 下载的一部分,位于http://java.sun.com/performance/jvmstat/

这比阅读 GC 日志要容易得多。

它可以快速帮助您了解堆的各个部分(代)是如何工作的。虽然您的总堆可能是 10GB,但堆的各个部分会小得多。堆的 Eden 部分中的 GC 相对便宜,而老年代中的完整 GC 成本较高。调整堆大小以使 Eden 很大并且老年代几乎不会被触及是一个不错的策略。这可能会导致一个非常大的整体堆,但是,如果 JVM 从不接触该页面,它只是一个虚拟页面,并且不必占用 RAM。

于 2008-10-28T19:05:07.313 回答
1

Sun 关于 Java 6 的文章可以帮助您:https ://www.oracle.com/java/technologies/javase/troubleshooting-javase.html

于 2008-10-18T04:37:58.263 回答
0

The max memory that XP can address is 4 gig(here). So you may not want to use XP for that(use a 64 bit os).

于 2008-10-18T02:51:17.073 回答
0

尽管 itanium 不是一个受欢迎的目的地,但 sun 已经拥有一个 itanium 64 位 jvm 有一段时间了。solaris 和 linux 64 位 JVM 应该是您应该追求的。
一些问题

1)您的应用程序稳定吗?
2) 您是否已经在 32 位 JVM 中测试过该应用程序?
3) 可以在同一个盒子上运行多个 JVM 吗?

我预计 Windows 的 64 位操作系统会在大约一年左右的时间内变得稳定,但在那之前,solaris/linux 可能是更好的选择。

于 2008-10-18T04:23:35.390 回答