有没有人有使用Java中12 GB或更高的大堆的经验?
GC是否使程序无法使用?
您使用什么GC参数?
哪个JVM,Sun或BEA更适合这个?
哪种平台,Linux或Windows,在这种情况下表现更好?
在Windows的情况下,在如此高内存负载下64位Vista和XP之间是否存在任何性能差异?
小智.. 72
如果您的应用程序不是交互式的,并且GC暂停对您来说不是问题,那么64位Java应该没有任何问题来处理非常大的堆,即使在数百GB中也是如此.我们也没有注意到Windows或Linux上的任何稳定性问题.
但是,当你需要保持GC暂停时,事情变得非常糟糕:
忘记默认吞吐量,停止世界GC.对于中等堆(<~30 GB),它将暂停应用几十秒,对于大堆(> ~30 GB),它将暂停几分钟.购买更快的DIMM无济于事.
最好的选择可能是CMS收集器,由-XX启用:+ UseConcMarkSweepGC.CMS垃圾收集器仅在初始标记阶段和重新标记阶段停止应用程序.对于像<4 GB这样的非常小的堆,这通常不是问题,但对于产生大量垃圾和大堆的应用程序,重新标记阶段可能需要相当长的时间 - 通常远远少于完全停止世界,但对于非常大的堆仍然可能是一个问题.
当CMS垃圾收集器的速度不足以在终生代填满之前完成操作时,它会回落到标准的stop-the-world GC.对于大小为16 GB的堆,预计大约30次或更长时间的暂停.您可以尝试避免这种情况,尽可能降低应用程序的长寿命垃圾生产率.请注意,运行应用程序的核心数越多,问题就越大,因为CMS只使用一个核心.显然,要注意不能保证CMS不会回退到STW收集器.当它发生时,它通常发生在峰值负载,并且您的应用程序已经死了几秒钟.您可能不希望为这样的配置签署SLA.
好吧,有新的G1事情.它的理论设计是为了避免CMS的问题,但我们已经尝试过并观察到:
它的吞吐量比CMS差.
从理论上讲,它应该首先避免收集流行的内存块,然而它很快就会达到几乎所有块都"受欢迎"的状态,并且基于它的假设只是停止工作.
最后,对于G1来说,世界末日的后备仍然存在; 问Oracle是否应该运行该代码.如果他们说"从不",请问他们,为什么代码在那里.所以恕我直言G1真的没有让Java的巨大堆问题消失,它只会让它(可以说)更小一些.
如果你有一个拥有大内存的大型服务器,那么你可能还需要一个好的,商业硬件加速,无间歇的GC技术,就像Azul提供的那样.我们有一台带有384 GB RAM的服务器,它确实工作正常 - 没有暂停,在GC中停止0行的世界各地的代码.
写下应用程序的该死的部分,需要大量的C++内存,就像LinkedIn使用社交图处理一样.你仍然不会通过这样做来避免所有的问题(例如堆碎片),但是将暂停保持在低位肯定会更容易.
Scott Seller.. 17
我是Azul Systems的首席执行官,所以我对这个话题显然有偏见!:) 话虽如此...
Azul的首席技术官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暂停.
如果您的应用程序不是交互式的,并且GC暂停对您来说不是问题,那么64位Java应该没有任何问题来处理非常大的堆,即使在数百GB中也是如此.我们也没有注意到Windows或Linux上的任何稳定性问题.
但是,当你需要保持GC暂停时,事情变得非常糟糕:
忘记默认吞吐量,停止世界GC.对于中等堆(<~30 GB),它将暂停应用几十秒,对于大堆(> ~30 GB),它将暂停几分钟.购买更快的DIMM无济于事.
最好的选择可能是CMS收集器,由-XX启用:+ UseConcMarkSweepGC.CMS垃圾收集器仅在初始标记阶段和重新标记阶段停止应用程序.对于像<4 GB这样的非常小的堆,这通常不是问题,但对于产生大量垃圾和大堆的应用程序,重新标记阶段可能需要相当长的时间 - 通常远远少于完全停止世界,但对于非常大的堆仍然可能是一个问题.
当CMS垃圾收集器的速度不足以在终生代填满之前完成操作时,它会回落到标准的stop-the-world GC.对于大小为16 GB的堆,预计大约30次或更长时间的暂停.您可以尝试避免这种情况,尽可能降低应用程序的长寿命垃圾生产率.请注意,运行应用程序的核心数越多,问题就越大,因为CMS只使用一个核心.显然,要注意不能保证CMS不会回退到STW收集器.当它发生时,它通常发生在峰值负载,并且您的应用程序已经死了几秒钟.您可能不希望为这样的配置签署SLA.
好吧,有新的G1事情.它的理论设计是为了避免CMS的问题,但我们已经尝试过并观察到:
它的吞吐量比CMS差.
从理论上讲,它应该首先避免收集流行的内存块,然而它很快就会达到几乎所有块都"受欢迎"的状态,并且基于它的假设只是停止工作.
最后,对于G1来说,世界末日的后备仍然存在; 问Oracle是否应该运行该代码.如果他们说"从不",请问他们,为什么代码在那里.所以恕我直言G1真的没有让Java的巨大堆问题消失,它只会让它(可以说)更小一些.
如果你有一个拥有大内存的大型服务器,那么你可能还需要一个好的,商业硬件加速,无间歇的GC技术,就像Azul提供的那样.我们有一台带有384 GB RAM的服务器,它确实工作正常 - 没有暂停,在GC中停止0行的世界各地的代码.
写下应用程序的该死的部分,需要大量的C++内存,就像LinkedIn使用社交图处理一样.你仍然不会通过这样做来避免所有的问题(例如堆碎片),但是将暂停保持在低位肯定会更容易.
我是Azul Systems的首席执行官,所以我对这个话题显然有偏见!:) 话虽如此...
Azul的首席技术官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暂停.
我们有一个应用程序,我们分配12-16 Gb但在正常操作期间它实际上只达到8-10.我们使用的是Sun JVM(尝试了IBM,它有点像灾难,但我们可能一直都是无知......我有朋友发誓 - 在IBM工作).只要您为应用程序提供喘息空间,JVM就可以处理大堆大小而不需要太多GC.大量"额外"记忆是关键.
Linux几乎总是比Windows更稳定,当它不稳定时,找出原因要容易得多.Solaris也很坚固,你也可以获得DTrace :)有了这样的负载,为什么你会使用Vista或XP呢?你只是在寻找麻烦.我们对GC params没有任何想象力.我们确实将最小分配设置为等于最大值,因此它不会一直尝试调整大小,但就是这样.
我在Linux和Solaris下分别使用64位版本(显然)的Sun 1.6 JVM在两个不同的应用程序上使用了超过60 GB的堆大小.
我从来没有遇到过基于Linux的应用程序的垃圾收集问题,除非在堆大小限制附近向上推.为了避免该场景固有的颠簸问题(花费太多时间进行垃圾收集),我只是优化了整个程序的内存使用量,以便峰值使用率比64 GB堆大小限制低约5-10%.
但是,在Solaris下运行不同的应用程序时,我遇到了很多垃圾收集问题,因此需要进行大量的调整.这主要包括三个步骤:
通过-XX:+ UseParallelGC -XX:+ UseParallelOldGC JVM选项启用/强制使用并行垃圾收集器,以及通过-XX:ParallelGCThreads选项控制使用的GC线程数.有关更多详细信息,请参阅" Java SE 6 HotSpot虚拟机垃圾收集调整 ".
在不再需要局部变量之后,将局部变量广泛且看似荒谬地设置为"null".其中大多数是在超出范围后应该有资格进行垃圾收集的变量,并且它们不是内存泄漏情况,因为没有复制引用.然而,出于某种原因,这种用于帮助垃圾收集的"手持式"策略是出于某种原因而无法解决的问题.
在经过大量临时对象分配后,在关键代码段中选择性地使用System.gc()方法调用.我知道反对使用这些调用的标准警告,以及它们通常不必要的论点,但我发现它们在运行这个内存密集型应用程序时对于驯服垃圾收集至关重要.
上述三个步骤使得可以保持此应用程序的运行效率大约为60 GB堆,而不是失控,直到达到128 GB的堆大小限制.并行垃圾收集器特别有用,因为当存在大量对象时主要的垃圾收集周期很昂贵,即主要垃圾收集所需的时间是堆中对象数量的函数.
我无法评论这种规模的其他平台特定问题,也没有使用非Sun(Oracle)JVM.
对于像Sun的Hotspot这样体面的JVM实现,12Gb应该没问题.我建议你在使用SUN VM时使用Concurrent Mark和Sweep colllector(-XX:+ UseConcMarkSweepGC).在GC期间,所有线程都会停止,因此你可能会面临很长时间的"停止世界"阶段.
操作系统不应该对GC性能产生很大影响.
当然,您需要一个64位操作系统和一台具有足够物理RAM的机器.
我建议还考虑进行堆转储,看看应用程序中的内存使用情况可以改进,并在Eclipse的MAT中分析转储.MAT页面上有一些关于开始寻找内存泄漏的文章.您可以使用jmap获取转储,例如...
jmap -heap:format=b pid