如果应用程序运行很长时间,则会丢失类

时间:2012-09-13 03:39:06

标签: scala jvm classloader noclassdeffounderror

我有一个有趣的问题 - 如果我的应用程序运行了很长时间(> 20h),那么有时我会得到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

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

造成这个问题的原因是什么?

1 个答案:

答案 0 :(得分: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返回一个类(这是错误的),但如果已知父级已经失败,那么这可能没有实际意义。因为这是我晚上的中间,我无法得出结论,但如果我的构建工具依赖于这种行为,我想要确定下来。

我不知道你的build.scala(或av.scala)中运行了一天的是什么,但也许你已经被一个行为不端的子类加载器装载了Avalanche(重新),然后当它抛出时, CL找不到你的ErrorHandler。