首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在长时间运行的进程中,什么会导致突然的ClassNotFoundException?

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

Stack Overflow用户
提问于 2013-09-10 05:02:05
回答 2查看 3.1K关注 0票数 19

我们有一个非常小的Web服务(少于1K行代码),它是由Jetty运行的。即使在我们的压力测试阶段,服务也总是工作得很好。然而,在13天的正常运行时间后,我们在同一天的两个节点中遇到了ClassNotFoundException。

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

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

详情:

  • 使用java HotSpot(TM) 64位服务器VM (内部版本16.3-b01,混合模式)
  • 使用jetty-runner-8.1.0.RC5.jar
  • 原始命令行: Java -Xmx2048M -jar jetty-runner-8.1.0.RC5.jar --port 5000 webapp.war
  • 英特尔至强E5-2680 8核(x2) +16 in内存

<代码>H111Red Hat Enterprise Linux6<代码>H212<代码>H113正在使用的一些框架: JBoss Resteasy,Spring IoC,Guava.<代码>H214<代码>F215

您能提供一些想法,让JVM突然“忘记”以前加载的类的存在,而不能再次加载它吗?

代码语言:javascript
复制
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连接断开,则文件句柄将无效,重新加载将失败,并显示类似的堆栈跟踪。在我们的例子中,我们使用的是Linux,所有涉及到的文件都在同一个挂载中,这是一个本地硬盘。为了进行更多的测试,我在Jetty临时目录中执行了CD操作,并手动删除了一个已知的特定服务类别。如果JVM卸载它,然后尝试从classes目录中重新加载它,那么它将失败。虽然这不能解释最初的问题,但它可能会提供更多的信息……

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-09-17 09:11:35

这就是正在发生的事情:

  1. 当使用上面详细介绍的命令启动服务时,Jetty会在"/tmp“下创建一个子目录,其中包含由JVM加载的应用程序类和资源。
  2. 在一段时间(在我们的特定场景中,在13到20天之间)不活动后,该目录将消失。因此,JVM无法加载该文件。我们仍然不知道JVM是否在这个错误之前卸载了这个类,或者为什么它试图重新读取*.class文件。查看源代码并了解这一点会很有趣,但这不在我们的短期ToDo列表中。
  3. 只需重新启动Jetty,就会重新创建丢失的目录,然后该服务再次启动。

我们得到的一个很好的提示是,一些人在Windows上通过NFS加载JAR中的资源时报告了类似的问题(如果网络连接短暂中断,NFS句柄就会无效,JVM会失败并出现类似的错误)。这不是我们的情况(/tmp是本地存储),但非常相似。

感谢大家的帮助。

票数 8
EN

Stack Overflow用户

发布于 2013-09-12 17:16:42

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

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

这与这个类已经通过另一个ClassLoader加载的事实并不冲突。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18706970

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档