如何选择jvm堆大小?

我通常对jvm堆大小做的是将max值设置得非常高,以避免臭名昭着的OutOfMemoryException。

然而,这种策略(或缺乏策略)似乎并不是很聪明。 :-)。

我的问题是如何选择最小值和最大值,以及两者之间的差异(最大值应该是小还是大?)。 例如,从这里 :

如果初始堆太小,Java应用程序启动变慢,因为JVM被迫频繁执行垃圾收集,直到堆增长到更合理的大小。 为获得最佳启动性能,应将初始堆大小设置为与最大堆大小相同。

谢谢。

我的问题是如何选择最小值和最大值,以及两者之间的差异(最大值应该小还是大?)

简短的回答:不要猜测,描述您的应用程序。

jconsole可以为您提供有用的高级数据,例如主要驻留集的感觉与我们通常分配的垃圾数据和垃圾收集。 如果你看一下该显示器的内存选项卡,你会看到的东西通常就像锯齿一样。 锯齿的下角大约是我通常设置最小堆的位置,而我会使用锯齿的峰值或斜率来试验堆最大值。 如果你的牙齿非常陡峭,你可能会考虑一大堆来延迟垃圾收集。 但是,如果不是,则可以尝试使用较小的堆最大值来查看是否可能为计算机上的其他进程留下更多资源(例如)。

您还应该将服务器VM视为会导致不同的垃圾回收行为。

总而言之,您还应该使用更详细的工具(如jvisualvm)来分析流程的内存使用情况 。 您可能有内存泄漏或贪婪的分配器,您可以调整或消除。 这将完全改变你的堆需求。

您应该启用GC日志记录并检查OOM的开销位置。

-verbose:gc -Xloggc:gc.log -XX:+PrintGCTimeStamps -XX:+PrintGCDetails 

您可能正在经历烫发空间限制,通过-XX:MaxPermSize=YYYm调整

无论如何回答你的问题,我从没有最小值开始,并设置相对较高的最大值。 然后我绘制gc日志图并找出我的替身状态; 在视觉上为不同代人选择高于平均水平的尺寸。 阅读它就像一张金融图表,你会希望看到新一代的良好传播以及终身一代的持续增长和collections。 如上所述,还要绘制你的烫发空间,以确保你不会不断增加。

GC调整是一门艺术,绝不是一门科学。

事实上,盲目地设定一个巨大的最大值并不是一个好主意(措施,不要猜测),这种策略将导致很长的“停止世界”主要的GC,从用户体验的角度来看可能并不可取(始终牢记“堆越大,主要GC越长”。

也就是说,您的问题没有通用的答案,每个应用程序都有不同的需求。 实际上,我建议对应用程序进行概要分析并调整堆,以便在(主要)GC频率和(主要)GC持续时间之间找到良好的折衷,同时最大限度地缩短对最终用户的响应时间。 我热烈建议您阅读Kirk Pepperdine的这篇精彩博文 (以及其他所有文章 )以获取更多详细信息。

只是为了回答最小值和最大值部分,我总是使用相同的值(为了更好的启动性能和更好的再现性)。

正确的答案是:每个项目都没有正确的答案 ,您必须在每个项目的基础上微调堆大小配置。 我会从小开始逐渐增加堆大小,直到您的应用程序按预期运行。

你是对的,设置一个巨大的最大值并不是一个好主意。

如果您遇到OOME,我实际上会尽可能多地增加最大内存,看看是否能解决问题。 首先让您的机器解决性能问题。 如果问题仍然存在,那么您可以查看性能诊断以识别瓶颈并处理应用程序可能泄漏或可能占用大部分内存的区域。

杰夫阿特伍德有一篇关于CodingHorror的好文章解释了这种态度; 对于性能问题,最具成本效益的解决方案是在将开发人员的时间投入到故障排除之前抛出硬件(或者在这种情况下,增加内存资源)。

http://www.codinghorror.com/blog/archives/001198.html

“忽略-Xms参数”是一个非常糟糕的主意,因为通常在同一个盒子上运行其他应用程序和进程。 您希望应用程序以分配的最大RAM量启动,因此如果失败,则在您查看启动日志时失败,而不是在凌晨4:00,当另一个应用程序占用了额外的RAM时,并且你的JVM的大小不能增长。

简而言之,总是设置JVM min并将大小混合为相同的值。