在 WildFly 中取消部署时,静态字段通常会被卸载吗?

Are static fields normally unloaded on undeployment in WildFly?

我正在使用 WildFly 11 Final,并创建了以下 EJB:

@Singleton
@Startup
public class MyDebug {
    private static final MyStaticSingleton myStaticSingleton = new MyStaticSingleton();
}

现在,如果我重新部署应用程序并通过 JVisualVm 查看堆,我将在每次重新部署时看到一个 MyStaticSingleton 实例。 MyStaticSingleton 的实例由不同的 ClassLoader 引用。

JavaEE 应用程序的类加载器在应用程序卸载后不被丢弃是正常行为吗?

很可能是由于应用程序的某些不当行为造成的泄漏。 事实上,这是一个很普遍的问题。

主要问题不是单例实例的数量增加,而是类加载器数量的增加,因此加载的数量 类(最终可能会很大)。您可以使用 javacore 转储轻松证明这一点。

要解决这个问题,您必须找到一个对象来防止这些类加载器中的每一个被丢弃,因此所有加载的 类。

EE 应用程序此类错误行为的一个众所周知的示例是使用启用了关闭挂钩(默认启用)的 log4j。

更新

只是为了确认,给定示例中的静态引用对象不会导致提到的类加载器/本机内存泄漏。 此外,由于静态字段声明为 final - 它符合 EJB 规范。

正如 TS 所提到的,主要嫌疑人是连接池,它 运行 它自己的线程违反了 EJB 规范。

在 EE 环境中使用线程,尤其是与上下文类加载器一起使用,是此类泄漏的典型原因。

EJB 3.2 规范 (16.2.2) 对此有明确规定:您不能这样做!

An enterprise bean must not use read/write static fields. Using read-only static fields is allowed. Therefore, it is recommended that all static fields in the enterprise bean class be declared as final.

只需为您的单例使用常规字段并将创建移动到 @PostConstruct。 如果单例也是托管的,请在此字段上使用注入。