Java 8 Metaspace: OutOfMemoryError: Dealing with reflection Inflation

Java 8 Metaspace: OutOfMemoryError: Dealing with reflection Inflation

网络上有很多links and open Q&A,但我仍然缺少很多信息。

要事第一

问题:

java.lang.OutOfMemoryError: Metaspace

jvm:

java version:  "1.8.0_131"
vm:             Java HotSpot(TM) 64-Bit Server
vm args:       -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=128m

框架:

spring, hibernate, wicket, jetty

嫌疑人 1:

在使用期间,metaspace逐渐增长,随后的反射类按比例加载到metaspace中[通过jmap -histo cron jobs观察]

sun.reflect.GeneratedConstructorAccessor1299
sun.reflect.GeneratedMethodAccessor6929
sun.reflect.GeneratedSerializationConstructorAccessor4220

可能的解决方案:

一个。由于我们正在使用大量处理反射内容的库,因此我们认为 128m 不足以容纳 metaspace 中所有生成的 XX 类。所以我们计划将 metaspace 限制加倍。 -XX:MaxMetaspace大小=256m

b。我们考虑设置以下

-D sun.reflect.noInflation

-D sun.reflect.inflationThreshold

嫌疑人2:

Full GC 持续 运行 甚至在 reaches/occupies 完整配置的元 space(128m) 之前,应用程序变成 unresponsive/slow/sometime OOM,因为 jvm 只会FGC.

[Full GC (Metadata GC Threshold) [PSYoungGen: 224K->0K(698368K)] [ParOldGen: 52910K->52933K(1398272K)] 53134K->52933K(2096640K), [Metaspace: 92733K->92733K(1163264K)], 0.1964143 secs] [Times: user=0.59 sys=0.00, real=0.19 secs]

.

Metaspace used 147414K, capacity 155731K, committed 159616K, reserved 1187840K
class space used 17242K, capacity 19252K, committed 20352K, reserved 1048576K

可能的解决方案:

-XX:CompressedClassSpaceSize 未在 vm 启动时明确提及,这可能会导致过度保留地址 space,从而导致误导性提交空间,从而引发 Full GC。如此明确地设置 -XX:CompressedClassSpaceSize=256m 将帮助 vm 正确规划和保留内存。

问题:

  1. 怀疑 1:是否有人遇到过类似问题并得到了解决?
  2. 怀疑2:设置-XX:CompressedClassSpaceSize真的会影响metaspace planning/reserving并影响GC吗?有什么指点吗?
  3. 还有其他嫌疑人吗?推荐?

花了这么多时间,结果发现没有 class 泄漏,我们是

的受害者

"Reflection Inflation"

package sun.reflect;

/**
 The master factory for all reflective objects, both those in
 java.lang.reflect (Fields, Methods, Constructors) as well as their
 delegates (FieldAccessors, MethodAccessors, ConstructorAccessors).
**/

public class ReflectionFactory {


    // "Inflation" mechanism. Loading bytecodes to implement Method.invoke() and Constructor.newInstance() currently costs
    // 3-4x more than an invocation via native code for the first invocation (though subsequent invocations have been benchmarked
    // to be over 20x faster). Unfortunately this cost increases startup time for certain applications that use reflection
    // intensively (but only once per class) to bootstrap themselves. To avoid this penalty we reuse the existing JVM entry points
    // for the first few invocations of Methods and Constructors and then switch to the bytecode-based implementations.

我亲身验证过,在每16次反射生成时使用这个技术来提高响应时间。

最后我们增加了元空间,一切似乎都正常。