6

我有一个有趣的问题——如果我的应用程序运行了很长时间(> 20 小时),那么有时我会收到 NoClassDefFound 错误——似乎 JVM 决定无论如何都不会使用该类并 GCd 它。

更具体地说,这是一个示例:

object ErrorHandler extends PartialFunction[Throwable,Unit] {
  def isDefinedAt(t: Throwable) = true
  def apply(e: Throwable) =e match {
    // ... handle errors
  }
}

// somewhere else in the code...
try {
  // ... long running code, can take more than 20 hours to complete
} catch (ErrorHandler)

我得到以下异常:

Exception in thread "main" java.lang.NoClassDefFoundError: org/rogach/avalanche/ErrorHandler$

如果该 try/catch 块运行的时间更短,那么一切都会按预期进行。

如果有人感兴趣,这里是有问题的代码库:Avalanche

我需要注意的是,我只在Cent OS 5使用 JRE 6u26 和 Scala 2.9.1 / 2.9.2 的机器上看到了这个和类似的问题。

这个问题的原因可能是什么?

4

1 回答 1

1

如果您在尝试初始化一个类时内存不足,您认为您会看到 OutOfMemory 还是 NoClassDef?

  //from initialize_impl
  if (NULL == message) {
    // Out of memory: can't create detailed error message
    THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);

您的代码可能引发 OOM,然后无法加载您的异常处理程序对象。

当然,还有其他可能的瞬态条件:网络中断,班级在网络驱动器上;或者你在测试期间清理了你的类目录。另一种可能性是您在不区分大小写的文件系统上构建了您的应用程序,并且正在使用异常命名的类文件在区分大小写的文件系统上进行测试。例如,如果您将对象“handler”更改为“Handler”而不删除 *.class,您仍然会看到“Handler.class”。(但我怀疑错误消息详细信息会包含名称冲突;当然,除非您是 OOM。)

我还没有机会尝试破坏 AbstractFileClassLoader;我之前的猜测如下:

值得解释的是,Avalanche 是一个构建工具,您运行一个 scalac 实例将 build.scala 编译为一个内存中的类文件,该类文件由 scalac 的 AbstractFileClassLoader 加载,其中“AbstractFile”是抽象。由于任何 build.scala 都与工具配置混为一谈,显然 AFCL 尊重类加载器委托是必不可少的。这似乎是真的,但我注意到它并没有首先委托给 getResourceAsStream 上的父级(正如快速测试所证实的那样)。可疑的是 findClass 使用了 classBytes,失败时调用 super,这是很好的 ScalaClassLoader,但它使用 getResourceAsStream 来加载 Foo.class。因此调用 findClass 可能会从父 CL 返回一个类(这是错误的),但如果已知父 CL 已经失败,这可能没有实际意义。因为它'

我不知道运行一天的 build.scala(或 av.scala)中有什么,但也许你已经通过行为不端的子类加载器加载了 Avalanche(重新),然后当它抛出时,CL 可以' t findClass 你的ErrorHandler。

于 2012-09-13T11:13:39.103 回答