java - 什么可能导致 JVM 崩溃并显示 SIGSEGV "ClassLoaderData::metaspace_non_null()"

标签 java memory jvm spring-cloud segmentation-fault

我们在一台机器上运行大约 40 个 JVM 进程 (3.2.0-4-amd64 #1 SMP Debian 3.2.78-1 x86_64 GNU/Linux)。服务器有 32GB 内存,每个进程消耗 350 到 380MB 内存。每个进程都托管一个 Spring Boot 应用程序。有时,我们会看到其中一个 JVM 崩溃并出现以下错误。

#  SIGSEGV (0xb) at pc=0x00007f151891d5d0, pid=3049, tid=0x00007f14fa784700
# JRE version: Java(TM) SE Runtime Environment (8.0_92-b14) (build 1.8.0_92-b14)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.92-b14 mixed mode linux-amd64 compressed oops)

V  [libjvm.so+0x4685d0]  ClassLoaderData::metaspace_non_null()+0xc0
V  [libjvm.so+0x8a17e0]  Metaspace::allocate(ClassLoaderData*, unsigned long, bool, MetaspaceObj::Type, Thread*)+0x170
V  [libjvm.so+0x8b4b46]  MethodCounters::allocate(ClassLoaderData*, Thread*)+0x26
V  [libjvm.so+0x8ac8b1]  Method::build_method_counters(Method*, Thread*)+0x71
V  [libjvm.so+0x681adb]  InterpreterRuntime::build_method_counters(JavaThread*, Method*)+0x2b
j  sun.reflect.GeneratedSerializationConstructorAccessor18988.newInstance([Ljava/lang/Object;)Ljava/lang/Object;+0
J 10626 C2 org.springframework.aop.framework.CglibAopProxy.getProxy(Ljava/lang/ClassLoader;)Ljava/lang/Object; (405 bytes) @ 0x00007f1509f7cca8 [0x00007f1509f77ec0+0x4de8]
J 11391 C2 org.springframework.cloud.netflix.eureka.DataCenterAwareMarshallingStrategy$PublishingApplicationsConverter.unmarshal(Lcom/thoughtworks/xstream/io/HierarchicalStreamReader;Lcom/thoughtworks/xstream/converters/UnmarshallingContext;)Ljava/lang/Object; (39 bytes) @ 0x00007f1509a8fee4 [0x00007f1509a8f4c0+0xa24]
J 11352 C2 org.springframework.cloud.netflix.eureka.DataCenterAwareMarshallingStrategy.unmarshal(Ljava/lang/Object;Lcom/thoughtworks/xstream/io/HierarchicalStreamReader;Lcom/thoughtworks/xstream/converters/DataHolder;Lcom/thoughtworks/xstream/converters/ConverterLookup;Lcom/thoughtworks/xstream/mapper/Mapper;)Ljava/lang/Object; (30 bytes) @ 0x00007f1509a344cc [0x00007f1509a33da0+0x72c]
J 12523 C2 com.sun.jersey.api.client.ClientResponse.getEntity(Ljava/lang/Class;Ljava/lang/reflect/Type;)Ljava/lang/Object; (246 bytes) @ 0x00007f150a3cbf94 [0x00007f150a3cb0e0+0xeb4]
J 11327 C2 com.netflix.discovery.DiscoveryClient.fetchRegistry(Z)Z (409 bytes) @ 0x00007f1509b4e7f0 [0x00007f1509b4e400+0x3f0]
J 11332 C2 com.netflix.discovery.DiscoveryClient$CacheRefreshThread.run()V (353 bytes) @ 0x00007f1509b49004 [0x00007f1509b48f60+0xa4]
...

这种情况发生在不同服务和不同机器上的进程中,没有任何明显的原因。但我们看到 Eureka 客户端尝试解码来自服务器的响应的堆栈跟踪始终相同。但如果它只是在这里失败的话我们不会这样做,因为

  1. 代码中的一些奇怪的星座(Spring、cglib、xstream、Eureka,...)
  2. 这很可能发生在这里,因为发现客户端始终每 30 秒轮询一次服务器,并且很可能会遇到系统中奇怪的星座(内存分配、碎片……)<

虽然我们使用的是Oracle JDK,但出于绝望我检查了the OpenJDK implementation的方法,但没有立即知道可能出了什么问题。

我向 Oracle 提交了一份错误报告,并与他们交换了几封电子邮件,但除了说如果没有这个问题的重现者,他们什么也做不了之外,我没有得到他们的回复。

所以我的问题是——有哪些可能的原因会导致 JVM 中出现这样的错误?当我们之前在内存较少、可用内存约为 2% 的系统上看到此错误时,我们怀疑内存碎片过高,但我发现在内存消耗仅为 70% 左右的新系统上不太可能出现这种情况。除了 JVM 实现中的错误之外,还有哪些其他原因可以解释此失败?最重要的是 - 我们可以尝试什么来可靠地重现此错误?

最佳答案

如果您提供完整的崩溃报告,那就太好了。 从这个小堆栈跟踪中我看到一个有趣的部分

sun.reflect.GeneratedSerializationConstructorAccessor18988

这意味着您的应用程序中有 18988 个生成的访问器(我认为这很多)。您可以在此处查看sun.reflect.MethodAccessorGenerator。 当您使用序列化或反射时,这可以生成新的类( sun.reflect.MethodAccessorGenerator#generate ),然后每个类将在 DelegatingClassLoder 中定义,每次都会创建该类( sun. Reflect.ClassDefiner#defineClass).

尝试提高通胀阈值

-Dsun.reflect.inflationThreshold = some big big number

它将推迟新访问器的生成。

<小时/>

您还可以通过 JMX 查看卸载了多少类( ClassLoading MBean ), 你也可以运行

jcmd %pid% PerfCounter.print

并监视计数器 sun.gc.metaspace.capacity sun.gc.metaspace.maxCapacity sun.gc.metaspace.used

关于java - 什么可能导致 JVM 崩溃并显示 SIGSEGV "ClassLoaderData::metaspace_non_null()",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37962583/

相关文章:

kubernetes - kubernetes pod 的写时复制式内存重用?使 pod 生成速度更快、内存效率更高

java - 在 Java 中有多少字节的字节码有一个特定的方法?

java - Hibernate Session 和线程安全

java - 在 Spring Boot 应用程序中添加条件外部 PropertySource

java - Spring Boot不读取application.properties

派生类的 C++ 数组与基类指向派生对象的指针数组 - 为什么分配的内存量如此不同?

c++ - 堆密集型 C++ 程序

java - 有什么理由不将 invokevirtual 和 invokeinteface 字节码指令合二为一吗?

java - Scala 开发人员应该了解 Java 和/或 JVM 的哪些方面?

java - 如何打印出所有线程及其当前状态?