java 最大堆大小,多少才算太多

java 最大堆大小,多少才算太多

我在 tomcat 中运行 JRuby (rails) 应用程序时遇到了问题。有时页面请求可能需要一分钟才能返回(尽管 rails 日志在几秒钟内处理了请求,所以这显然是 tomcat 的问题)。

我想知道哪些设置对于 Java 堆大小来说是最佳的。我知道没有明确的答案,但我想也许有人可以对我的设置发表评论。

我使用的是具有 1.7g RAM 的小型 EC2 实例。我有以下 JAVA_OPTS:

-Xmx1536m -Xms256m -XX:MaxPermSize=256m -XX:+CMSClassUnloadingEnabled

我首先想到的是 Xmx 太高了。如果我只有 1.7gb,而我为 java 分配了 1.5gb,我觉得我会得到很多分页。通常我的 java 进程(在顶部)显示 1.1g res 内存和 2g 虚拟内存。

我也读过某处将 Xms 和 Xmx 设置为相同的大小将有助于消除花在内存分配上的时间。

我不是 Java 爱好者,但我被委以重任来解决这个问题,我正在努力找出从哪里开始。任何建议都非常感谢!!

更新
我已经开始使用以下方法分析垃圾收集转储-XX:+PrintGCDetails

当我注意到这些偶尔出现的较长的加载时间时,gc 日志就会变得很疯狂。我做的最后一个(花了 25 秒才能完成)我有如下 gc 日志行:

1720.267: [GC 1720.267: [DefNew: 27712K->16K(31104K), 0.0068020 secs] 281792K->254096K(444112K), 0.0069440 secs]
1720.294: [GC 1720.294: [DefNew: 27728K->0K(31104K), 0.0343340 secs] 281808K->254080K(444112K), 0.0344910 secs]

单个请求中大约有 300 个!!!现在,我不完全理解为什么它总是从~28m 一直到 0 一遍又一遍地进行 GC'ng。

答案1

虽然我没有在 Tomcat 上运行任何 JRuby 应用程序,但我已经在各种 J2EE 应用服务器上运行过 ColdFusion 应用程序,并且也遇到过类似的问题。

这些常见问题解答,您会看到 SOracle 表示在 32 位 Windows 上,最大堆大小限制为 1.4 到 1.6 GB。我从来没有能够让它稳定地达到这么高的值,我怀疑你运行的配置也类似。

我的猜测是,您的请求需要很长时间才能运行,因为堆大小很高,JVM 分配的物理内存比 Windows 必须提供的多,因此 Windows 花费大量时间将页面从内存交换到磁盘,以便它可以为 JVM 提供所需的内存量。

我的建议是,尽管这违反直觉,但实际上应该将最大堆大小降低到 1.2 GB 左右。如果您注意到应用程序的请求处理速度变慢,而 JVM 必须向 Windows 请求更多内存来增加堆大小(因为堆中充满了未收集的对象),那么您也可以增加最小大小。

答案2

您的问题部分在于,您可能正在耗尽所有其他进程的内存。我的一般经验法则-Xms如下-Xmx

-Xms : <System_Memory>*.5
-Xmx : <System_Memeory>*.75

因此在 4GB 系统上它将是:-Xms2048m -Xmx3072m,并且对于你的情况我会选择-Xms896m -Xmx1344

答案3

除了前面的答案之外,您还应该考虑 PermGen。PermGen 不是堆空间的一部分。使用您当前的配置,您的 java 进程总计可达 1792mb,这是您机器的总量。

答案4

我知道已经有了一个答案,但我还是要解释一下。

首先,在您使用的命令行中,您已经为 Java 堆 (-Xmx1536m) 保留了 1536 兆字节,为 PermGen (-XX:MaxPermSize=256m) 保留了 256 兆字节。PermGen 与 Java 堆分开分配,用于存储在 JVM 中加载的 Java 类。

这两个区域加起来已经有 1792 兆字节的 RAM。

但除此之外,还需要 RAM 来加载 JVM 本身(JVM 的本机代码)和 RAM 来存储 JIT 编译器生成的代码。

我怀疑所有这些加起来就等于您提到的 2 GB 虚拟空间。

最后,您还必须考虑服务器上正在运行的其他需要 RAM 的东西。您并没有真正提到服务器上使用了多少交换空间。这会告诉您机器是否正在交换,这是否导致应用程序反应缓慢。您应该始终防止 JVM 触及交换空间。频繁触发垃圾收集器要比分配过多的堆并让部分 Java 堆被交换出去好得多。

相关内容