全部,
我正在使用openjdk 1.8.0_212-b04,Tomcat 8.0.21和Red Hat 6.4。
并且我已经调整了测试Web应用程序,请确保在重新部署后不会出现没有此类消息:
WARNING: The web application [Test] appears to have started a thread named [test-job_Worker-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread
这是我在测试中使用的GC参数:
-Xms2G -Xmx4G
-XX:MaxMetaspaceSize=1G -XX:CompressedClassSpaceSize=300
-Dsun.rmi.dgc.client.gcInterval=9223372036854775807
-Dsun.rmi.dgc.server.gcInterval=9223372036854775807
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:GCLogFile Size=10M -XX:NumberOfGCLogFiles=5 -Xloggc:$LOG_HOME/gc-$START_TIME.log
然后我使用了一个shell脚本来保持联系web.xml以重新部署该Web应用程序。测试期间没有其他流量/操作。
如图所示:在第1点,元空间会在某个时候缩小,因此我认为应该不存在元空间内存泄漏。
但是在第2点,Tomcat抛出了元空间OOM:
14-Jun-2019 09:26:32.184 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run Unexpected death of background thread ContainerBackgroundProcessor[StandardEngine[Catalina]]
java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2472)
at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:854)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1274)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157)
at org.apache.logging.log4j.status.StatusLogger.<init>(StatusLogger.java:108)
at org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:85)
at org.apache.logging.log4j.web.Log4jServletContextListener.<clinit>(Log4jServletContextListener.java:44)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
在第3点,我单击了VisualVM中的GC按钮,元空间实际上是可收缩的。
我尝试添加参数-XX:MaxMetaspaceFreeRatio = 60,但仍然得到了smae结果。
这是GC日志: GC Log
感谢您提供解决OOM错误/排除故障/调试的建议。
更新1: 感谢@samabcde的建议,我添加了se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor来进行更多测试。 它有助于删除一些ThreadLocal变量,并使Web应用程序保留更多时间。
14-Jun-2019 17:44:31.463 INFO [ContainerBackgroundProcessor[StandardEngine[Catalina]]] se.jiderhamn.classloader.leak.prevention.JULLogger.info Custom ThreadLocal of type org.springframework.core.NamedThreadLocal: Prototype beans currently in creation with value null will be remove()d from Thread[ContainerBackgroundProcessor[StandardEngine[Catalina]],5,main]
答案 0 :(得分:3)
在测试期间,我看到Metaspace几乎达到最大值,然后我停下来重新部署Web应用程序,并进行了堆转储,将其置于MAT下进行分析。
正如预期的那样,有许多WebappClassLoader。 但是我检查了它是 GC根目录的路径|排除所有相位/弱/软。等引用,这是GC根目录。
我检查了它是 GC根目录的路径|包含所有引用,那么GC根就不止一个。
所以...这些WebappClassLoader实际上是phatom / weak / soft。被其他对象引用时,它将留在堆中一段时间才能被释放。
然后我添加GC参数:-XX:SoftRefLRUPolicyMSPerMB = 10,可以将Web应用程序重新部署超过1000次...
问题就解决了!
PS。因为我们不会在生产环境中在短时间内重新部署Web应用程序,所以我们不会使用-XX:SoftRefLRUPolicyMSPerMB = 10。