我目前正在使用 Visual VM 监控正在运行的 java 应用程序:http: //visualvm.java.net/
我通过 -Xmx128m 来强调内存使用情况。
运行时,我看到堆大小增加到 128m(如预期的那样),但是在遇到 java 堆空间错误之前,使用的堆收敛到大约 105m。
为什么这些剩余的20m,没有使用?
我目前正在使用 Visual VM 监控正在运行的 java 应用程序:http: //visualvm.java.net/
我通过 -Xmx128m 来强调内存使用情况。
运行时,我看到堆大小增加到 128m(如预期的那样),但是在遇到 java 堆空间错误之前,使用的堆收敛到大约 105m。
为什么这些剩余的20m,没有使用?
您需要了解有关垃圾收集器人体工程学的一个核心事实:
垃圾收集成本高昂的部分是查找和处理不是垃圾的对象。
这意味着:随着堆接近其最大容量,GC 将花费越来越多的时间来回收越来越少的空间。如果 GC 尝试使用内存的最后一个字节,最终结果将是您的 JVM 将花费越来越多的时间进行垃圾收集,直到……最终……几乎没有任何有用的工作被完成。
为了避免这种病态的情况,JVM 监控用于 GC 和做有用工作的时间比例。当比率超过可配置的阈值时,GC 会引发OutOfMemoryError
... 即使(技术上)有可用的可用内存。这可能就是您所看到的,尽管其他解释同样合理。
您可以通过 JVM 选项更改 GC 阈值、生成大小等,但最好不要这样做。一个更好的主意是弄清楚为什么您的应用程序的内存使用量不断上升。很可能存在内存泄漏......即错误......在您的代码中导致这种情况。花你的精力去寻找和修复这些错误,而不是担心为什么你没有使用所有的内存。
(事实上,您正在使用它……但并非一直如此。)
Java 将其内存分成几代。如果老生代填满,您可能会收到堆空间错误。通常,它们会动态调整大小,但如果您设置了固定大小,则不会。
堆分为年轻代(Eden-Space,以及两个大小相同的 Survivor-Spaces,通常称为 From 和 To)、老年代(Tenured)和永久空间。
该Xmx/Xms
选项设置整体堆大小。所以一个区域(具有默认大小)实际上是永久空间 - 也许,我们不知道有关您的压力测试的详细信息,实际上没有对象从伊甸园移动到永久或永久,所以当伊甸园用完时,这些区域仍然是空的的空间。