3

在我的工作环境中,我们有许多在 Windows Server 2008 硬件上运行的企业 Java 应用程序。一位外部顾问一直在审查我们的 Java 应用程序的性能,并建议我们将初始内存值和最大内存值更改为相同。

所以,目前,我们正在运行一个初始内存为 1GB,最大内存为 2GB 的应用程序。他们的建议是将初始内存和最大内存都更改为 2GB。

他们的推理是2倍的......

  1. 通过将初始和最大值分配为 2GB,当 Java 应用程序启动时,它将直接获取 2GB 内存块。这可以防止任何其他应用程序访问此内存块,因此 Java 应用程序将始终可以使用此内存。这与目前的情况相反,它只会获得 1GB 的初始块,这意味着其他应用程序可能会消耗服务器上剩余的可用内存,而企业 Java 应用程序将无法增长到 2GB 内存最大。
  2. 每次 Java 需要在初始大小和最大大小之间分配内存时,都会对性能造成很小的影响。这是因为它需要转到 Windows,分配所需大小的新块,然后使用它。每次在初始大小和最大大小之间需要内存时,都会发生这种性能损失。因此,将它们都设置为相同的值意味着消除了这种性能影响。

我认为他们的第一点从安全角度来看是有效的,因为这意味着无论其他应用程序在服务器上做什么,Java 应用程序都将始终可以访问最大内存。但是,我也认为这可能是一个负面因素,因为这意味着有一大块内存不能被其他应用程序使用,如果他们需要它,这可能会导致一般的服务器性能问题。

我认为他们在第 2 点中讨论的性能影响可能微不足道,因此不值得担心。如果他们关心性能,他们最好调整诸如 Java 的垃圾收集方面的东西,而不是担心分配内存块对性能的微小影响。

谁能告诉我他们将初始内存和最大内存分配给相同值的请求是否有真正的好处。是否有任何一般性建议?

4

4 回答 4

3

IMO,即使是第一个建议也不那么重要。现代操作系统具有虚拟内存。因此,即使您为 Java 进程分配 2GB 内存,也不能保证这些 2GB 内存将始终驻留在物理内存中。如果同一个盒子里有其他应用程序消耗大量内存,那么无论何时分配内存,性能都会很差。

于 2012-05-03T00:58:49.673 回答
3

将它们设置为相同会增加可预测性。如果您在 GC 决定需要更多内存时不将它们设置为相同,则需要时间来分配和随机分配对象以腾出空间。这是对 GC 活动的补充。当这种情况发生时,请求会变慢,您的吞吐量会受到影响。在 2GB 堆上,每次需要更多内存时,您可能会分配大约 400mb 的内存,而每次不需要内存时会删除 100mb。增加堆大小,这些数字就会增加。堆将在您的值之间不断变化,它不像它只是分配并保留该内存。

对于关于确保操作系统始终为您提供可用内存的论点#1,我认为这是一个有争议的问题。如果您的服务器内存不足,并且您已经限制机器运行该软件,那么您在错误的服务器上运行它。获取您需要的硬件并为其提供发展空间。如果您说您的应用程序可以使用 2GB,那么我个人会在具有 4GB 或更多免费空间的机器上使用它。如果我的客户/用户群增长,则可以自由增加堆以容纳新用户。

于 2012-05-03T02:06:05.420 回答
2

第二点非常有效。抢内存是一个缓慢的 IO 操作。尤其是大块。但是,2GB 是一个大块。你在什么硬件上运行这个?如果它有相当多的内存,那将是一个好主意。

但是,假设您的计算机实际上并没有很多内存,分配 2GB 块可能是危险和贪婪的。相反,您应该创建一个对象池方案。请记住,垃圾收集器会占用内存并做自己的内存池,但在 2GB 的情况下,很可能会向操作系统释放一些内存。

做一些分析,你会惊讶于不浪费内存和一直分配内存可以节省多少时间。垃圾收集器会保护你免受很多垃圾的影响,但对于 2GB 的块来说并没有那么多。

最终,如果可能的话……您应该考虑使用 LESS 内存。为了获得真正的性能,请考虑将缓冲区和数组保留在缓存中。这有点复杂,但它可以产生巨大的结果。

祝你好运

于 2012-05-03T02:16:20.213 回答
1

当您启动 JVM 时,无论您是否设置初始大小,它都会将最大堆大小作为一个连续块来获取。它的使用量取决于使用情况。例如,初始大小为 2G 的 ..ga hello world 不会使用 2G。初始大小所做的不是尝试限制使用,直到达到初始大小。(但如果实际上不需要,它不会为其分配主内存)

设置初始值可以提高启动时间。我倾向于将初始大小设置为 JVM 增长到的大小(或者如果启动时间很短则不打扰)

真正的影响是,较小的堆大小可能会导致临时对象移入永久空间,清理起来代价高昂。较大的堆大小可能意味着临时对象在被多次复制并使用完整 gc 删除之前被丢弃。

于 2012-05-03T05:34:32.710 回答