我通常对jvm堆大小做的是将max值设置得非常高,以避免臭名昭着的OutOfMemoryException。
然而,这种策略(或缺乏战略)似乎并不是很聪明。 : - 。)
我的问题是如何选择最小值和最大值,以及两者之间的差异(最大值应该是小还是大?)。 例如,来自here:
如果初始堆太小,那么 Java应用程序启动变慢 因为JVM被迫执行 垃圾收集频繁,直到 堆已经增长到更多 合理的尺寸。为了最佳启动 性能你应该设置初始 堆大小与最大值相同 堆大小。
感谢。
答案 0 :(得分:19)
我的问题是如何选择分钟 和最大值,以及差异 两者之间(应该是最大 - 分钟 小还是大?)
简短回答:不要猜测,简介您的应用程序。
jconsole can give you useful high-level data,例如对主要居民设置的感觉与我们通常分配的垃圾收集的瞬态数据。如果你看一下该显示器的内存选项卡,你会看到的通常类似于锯齿。锯齿的下角是我通常设置最小堆的地方,而我会使用锯齿的峰值或斜率来试验堆最大值。如果你的牙齿非常陡峭,你可能会考虑一大堆来延迟垃圾收集。但是,如果不是这样,您可以尝试使用较小的堆最大值来查看是否可能为计算机上的其他进程留下更多资源(例如)。
您还应该将server VM视为会导致不同的垃圾收集行为。
所有这一切,您还应该使用更详细的工具,例如jvisualvm to profile the memory usage of your process。您可能有内存泄漏或贪婪的分配器,您可以调整或消除。这将完全改变你的堆需求。
答案 1 :(得分:5)
您应该启用GC日志记录并检查您的OOM发生的位置。
-verbose:gc
-Xloggc:gc.log
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
您可能正在遇到烫发空间限制,请通过-XX:MaxPermSize=YYYm
无论如何要回答你的问题,我从没有最小值开始,并设置相对较高的最大值。然后我绘制gc日志图并找出我的替代状态;在视觉上为不同代人选择高于平均水平的尺寸。像金融图表一样阅读它,你会希望看到新一代的良好传播以及终身一代的持续增长和收集。如上所述,还要绘制你的烫发空间,以确保你不会不断增加。
GC调整是一门艺术,绝不是一门科学。答案 2 :(得分:3)
事实上,盲目地设定一个巨大的最大值并不是一个好主意(措施,不要猜测),这个策略将导致很长的“停止世界”主要的GC,从用户体验点可能不是理想的视图(始终记住“堆越大,主要GC越长”)。
那就是说,你的问题没有通用的答案,每个应用程序都有不同的需求。实际上,我建议您分析您的应用程序并调整堆,以便在(主要)GC频率和(主要)GC持续时间之间找到良好的折衷,同时最大限度地缩短对最终用户的响应时间。我热烈建议您阅读Kirk Pepperdine的这篇伟大的blog post(及其他所有人)以获取更多详情。
为了回答最小值和最大值部分,我总是使用相同的值(为了更好的启动性能和更好的再现性)。
答案 3 :(得分:2)
正确的答案是:没有正确的答案每个项目都不同,您必须在每个项目的基础上微调堆大小配置。我会从小开始逐渐增加堆大小,直到你的应用程序按预期运行。
你是对的,设定一个巨大的最大值并不是一个好主意。
答案 4 :(得分:2)
如果您遇到OOME,我实际上会尽可能多地增加最大内存,看看是否能解决问题。首先让您的机器解决性能问题。如果问题仍然存在,那么您可以查看性能诊断以识别瓶颈并处理应用程序可能泄漏或可能占用大量内存的区域。
杰夫阿特伍德有一篇关于CodingHorror的好文章解释了这种态度;解决性能问题的最具成本效益的解决方案是在将开发人员的时间投入到故障排除之前抛出硬件(或者在这种情况下,增加内存资源):
答案 5 :(得分:2)
“忽略-Xms参数”是一个非常糟糕的主意,因为通常在同一个盒子上运行其他应用程序和进程。您希望应用程序以分配的最大RAM量启动,因此如果失败,则在您查看启动日志时失败,而不是在凌晨4:00,当另一个应用程序占用了额外的RAM时,并且你的JVM的大小不能增长。
简而言之,总是设置JVM min并将大小混合为相同的值。