Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在长时间运行的进程中,什么会导致突然发生ClassNotFoundException?_Java_Jvm_Noclassdeffounderror_Classnotfoundexception - Fatal编程技术网

Java 在长时间运行的进程中,什么会导致突然发生ClassNotFoundException?

Java 在长时间运行的进程中,什么会导致突然发生ClassNotFoundException?,java,jvm,noclassdeffounderror,classnotfoundexception,Java,Jvm,Noclassdeffounderror,Classnotfoundexception,我们有一个非常小的Web服务(少于1K行代码),由Jetty运行。即使在我们的压力测试阶段,该服务也始终运行良好。然而,经过13天的正常运行后,我们在同一天的两个节点中遇到了ClassNotFoundException 奇怪的是,找不到的类已经在那里了(它是启动例程的一部分,经常用于服务以前的请求)。事实上,只要重新启动流程就解决了问题。两个节点都位于不同的机器中,并且彼此独立。除了一个JMS连接之外,它们不依赖于外部资源 在谷歌搜索时,我找不到相关信息,因为大多数报告的问题都与启动Java进程

我们有一个非常小的Web服务(少于1K行代码),由Jetty运行。即使在我们的压力测试阶段,该服务也始终运行良好。然而,经过13天的正常运行后,我们在同一天的两个节点中遇到了ClassNotFoundException

奇怪的是,找不到的类已经在那里了(它是启动例程的一部分,经常用于服务以前的请求)。事实上,只要重新启动流程就解决了问题。两个节点都位于不同的机器中,并且彼此独立。除了一个JMS连接之外,它们不依赖于外部资源

在谷歌搜索时,我找不到相关信息,因为大多数报告的问题都与启动Java进程时类路径中缺少类有关,这不是我们的情况。我们怀疑可能存在某种程度上损坏JVM内存的内存泄漏,但是这无法解释为什么相同的问题同时发生在两个节点上。在过去的五天里,我们一直在进行密集的压力测试,附加了一个JVM监视器和一个内存泄漏分析器,一切似乎都很好。对于这个测试,我们将进程内存从2GB减少到512MB

详细信息:

  • 使用Java HotSpot(TM)64位服务器虚拟机(构建16.3-b01,混合模式)
  • 使用jetty-runner-8.1.0.RC5.jar
  • 原始cmd行:java-Xmx2048M-jarjetty-runner-8.1.0.RC5.jar——端口5000 webapp.war
  • 英特尔至强E5-2680 8核(x2)+16GB RAM
  • 红帽企业Linux 6
  • 正在使用的一些框架:JBossRestEasy、SpringIOC、Guava
您能否提供一些想法,让JVM突然“忘记”以前加载的类的存在,而不能再次加载它

Caused by: java.lang.ClassNotFoundException: com.a.b.c.SomeClass
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202) ~[na:1.6.0_37]
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.6.0_37]
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190) ~[na:1.6.0_37]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306) ~[na:1.6.0_37]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) ~[na:1.6.0_37]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247) ~[na:1.6.0_37]
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:424) ~[na:na]
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:377) ~[na:na]
    at java.lang.Class.forName0(Native Method) ~[na:1.6.0_37]
    at java.lang.Class.forName(Class.java:247) ~[na:1.6.0_37]
    at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:95) ~[na:1.6.0_37]
    at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:107) ~[na:1.6.0_37]
    at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:31) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseSig(AnnotationParser.java:370) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseClassValue(AnnotationParser.java:351) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:280) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:222) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:69) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:52) ~[na:1.6.0_37]
    at java.lang.reflect.Field.declaredAnnotations(Field.java:1014) ~[na:1.6.0_37]
    at java.lang.reflect.Field.getDeclaredAnnotations(Field.java:1007) ~[na:1.6.0_37]
编辑:


有人提到我在Win下使用NFS挂载时,JVM可能会决定卸载一个类,然后在需要时重新加载它。如果在这个过程中间,NFS连接被破坏,文件句柄将无效,重新加载将失败,类似的StAcTrace。在我们的例子中,我们使用的是Linux,所有涉及的文件都在同一个挂载中,即本地硬盘。为了进行更多的测试,我已经将CD放入Jetty临时目录,并手动删除了一个特定服务类的已知目录。如果JVM卸载它,然后尝试从classes目录重新加载它,它将失败。虽然这并不能解释最初的问题,但它可能会在表中提供更多信息…

堆栈跟踪告诉我们它是关于处理注释的,而不是与加载类以执行代码有关。注释处理器似乎试图通过注释元素的
ClassLoader
解析注释成员的值

换句话说,您有一个类类型值为
@Foo(xyz=ABC.class)
的注释,以及一个使用此构造进行注释的类或成员,但在运行时无法通过注释元素的
类加载器
访问类
ABC


这与该类已通过另一个
类加载器加载这一事实并不冲突

  • 当使用上面详述的cmd启动服务时,Jetty在“/tmp”下创建一个子目录,该目录保存JVM加载的应用程序类和资源
  • 在一段时间的不活动之后(在我们的特定场景中,13到20天之间),该目录将消失。因此,JVM无法加载该文件。我们仍然不知道JVM是否在这个错误之前卸载了这个类,或者为什么它试图重新读取*.class文件。查看源代码并了解这一点会很有趣,但这不在我们的短期待办事项列表中
  • 简单地重新启动Jetty会导致丢失的目录被重新创建,服务再次启动
  • 我们得到的一个很好的提示是,有些人在Windows上通过NFS在JAR中加载资源时报告了类似的问题(如果网络连接短暂中断,NFS句柄将无效,JVM将出现类似错误)。这不是我们的情况(/tmp是本地存储),但非常类似


    谢谢大家的帮助。

    stacktrace中还有更多行吗?可能是因为某些实例试图动态修改webapp容器的类路径。@Farid:是。上面的几行代码与未能加载类的Jackson反序列化程序有关(出于保密原因,我将其名称混淆为com.a.b.c.SomeClass)。出于同样的原因,我不能复制粘贴它。不过,我将很快编辑问题,添加更多信息。谢谢,我正在做的大多数项目也使用jackson,但从来没有像你那样出现过任何问题。我能看到的唯一区别是,我们通常使用tomcat而不是jetty,而且我从不为jackson使用注释。你认为你可以在tomcat实例下尝试放弃jetty的任何类路径修改机制,或者不为jackson添加任何注释(因为你的应用程序很小)?我可以想到的一个是热部署扫描程序,即jetty检测到你的应用程序文件有变化并重新加载整个类路径。如果正在使用,请禁用此功能主要问题仍然是为什么再次加载该类?您是否按照@gerrytan的建议禁用了热部署?听起来有点奇怪。你如何解释这个问题是在很长一段时间后才出现的,就像你写的那样,大约13天?我对EE框架/webservice的
    ClassLoader
    结构和活动知之甚少。是否涉及重新加载/重新部署?我认为,重新加载/重新部署的主要情况是当您启用了热部署并且一些资源发生了变化时,bu