我有一个分配了 20GB 堆内存的应用程序。但即使堆内存几乎没有使用或少于 50%,我的服务器交换空间也完全用完了。 Java 进程消耗了 90% 的交换空间。
只有在重新启动应用程序并出现以下警告后,交换才会被释放。寻找根本原因以及由此产生的任何影响。如果交换空间已满,我的应用程序会无法启动吗?
我在应用程序启动期间在日志中看到警告:
There is insufficient memory for the Java Runtime Environment to continue. Native memory allocation (mmap) failed to map 17895718912 bytes for committing reserved memory.. Out of swap space or heap resource limit exceeded (check with limits or ulimit)? An error report with more information is generated, it is saved as a file at this location: /XX/myapp/apache-tomcat-7.0.90/bin/hs_err_pid86282.log 2020-01-14T05:17:18.742+0100 [INFO] [o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker] Bean '(inner bean)#1814a032' of type [org.springframework.aop.aspectj.AspectJAroundAdvice] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) ***Warning: INFO: os::commit_memory(0x00000003fjgh0000, 17895718912, 0) failed; error='Not enough space' (errno=12) There is insufficient memory for the Java Runtime Environment to continue. Native memory allocation (mmap) failed to map 17895718912 bytes for committing reserved memory.. Out of swap space or heap resource limit exceeded (check with limits or ulimit)? An error report with more information is generated, it is saved as a file at this location:
我的 JVM 属性:
/XX/java/bin/java -Djava.util.logging.config.file=/XX/myapp/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -javaagent:/xx/myapp/newrelic/newrelic.jar -Djdk.tls.ephemeralDHKeySize=2048 -Xms20g -Xmx20g -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -Djava.net.preferIPv4Stack=true -Dignore.endorsed.dirs= -classpath /XX/myapp/tomcat/bin/bootstrap.jar:/XX/myapp/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/XX/myapp/tomcat -Dcatalina.home=/XX/myapp/tomcat -Djava.io.tmpdir=/XX/myapp/tomcat/temp org.apache.catalina.startup.Bootstrap start
检查每个进程的交换使用情况,其 Java 使用了 90% 的交换
最佳答案
您的 Java 进程不仅仅仅来自堆内存,请观看 this for a good example .
现在,您说您有 28GB
RAM,其中20GB
仅用于堆。您不仅保留虚拟内存,还通过 AlwaysPreTouch
提交虚拟内存(我现在怀疑您是否理解它的作用)。因此,您的操作系统将 20GB
RAM 映射到您的进程(简化解释)。
即使您看到只有 50%
被占用,您使用的垃圾收集器也不会将内存释放回操作系统,因此整个 20GC
总是被占用并且不能被其他进程重复使用。因此,测量或监视堆是没有意义的。
您的进程失败,并显示 native 内存分配(mmap)无法映射...
,如上所述,这与堆无关。它在 native 内存中失败,这是!=
堆。我也不知道您的应用程序的具体情况,但 -XX:+DisableExplicitGC
可能不是一个好的选择;相反,您可以通过 -XX:+ExplicitGCInvokesConcurrent
启用并发调用(如果您的 GC 支持)。
您似乎还在使用 CMS
垃圾收集器 - 已弃用。
关于jvm - Java 进程消耗 90% 的交换空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60112334/