java—由于类卸载,静态变量可以多次初始化吗?

xtupzzrd  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(671)

大家好,当我看了关于g1gc的演示时,我了解到,这个gc可以在收集垃圾的过程中使课堂变得轻松。想象一下,我们有这样一个班。

public class Foo {
   public static int a = 5;

}

让我们假设我们的代码中没有对这个类的任何引用,以便向gc说明这个类将不再被使用。为了进行类加载和初始化,我们定期访问 int a 变量。为了不在代码中有任何引用,我们通过反射在http请求调用的方法中执行这个变量的加入,方法的类名是param。
在这种情况下,或者任何类似的情况下,是否有可能多次初始化类?什么也意味着静态字段将多次初始化?
静态字段可以初始化几次吗?

o4hqfura

o4hqfura1#

这在中的规范中有说明§12.7. 卸载类和接口:
java编程语言的实现可以卸载类。
当且仅当垃圾收集器可以回收类或接口的定义类加载器(如中所述)时,才可以卸载类或接口§12.6.
不能卸载引导加载程序加载的类和接口。
规则的动机与你的问题直接相关:
类卸载是一种有助于减少内存使用的优化。显然,程序的语义不应该取决于系统是否以及如何选择实现类卸载之类的优化。否则会损害程序的可移植性。因此,类或接口是否被卸载对程序来说应该是透明的。

例如,如果类具有 static 变量(其状态将丢失)、静态初始值设定项(可能有副作用)或 native 方法(可以保持静态)。此外 Class 对象依赖于其标识。因此,一般来说,不可能以完全透明的方式重新加载类或接口。
因为我们不能保证卸载一个类或接口,而这个类或接口的加载程序可能是可访问的,所以卸载不会导致重新加载,而且重新加载从来都不是透明的,但是卸载必须是透明的,所以当一个类或接口的加载程序可能是可访问的时,不能卸载它。类似的推理可以用来推断引导加载程序加载的类和接口永远不会被卸载。
除了显式提到的bootstrap loader(它需要显式语句,因为它由 null ,因此可访问性是没有意义的),应用程序类加载器(也称为系统类加载器)始终是可访问的。这同样适用于它的父级,jdk之前的扩展类加载器 9和平台类加载器。
这意味着对于由应用程序加载器加载的普通应用程序及其所有直接依赖项,类卸载是不可能的。只有应用程序或框架创建的其他类加载器可能无法访问。
上述规范还规定:
类卸载是一种优化,它只对加载大量类并在一段时间后停止使用其中大多数类的应用程序有意义。这种应用程序的一个主要例子是web浏览器,但还有其他一些。此类应用程序的一个特点是,它们通过显式使用类装入器来管理类。因此,上述政策对他们很有效。
这个例子反映了java的历史,但是今天,一个主要的例子应该是一个应用服务器。在重新部署新版本时,甚至在使用新的类加载器再次加载相同的类文件时,它们在技术上是不同的类,卸载的透明度与此无关。
这包含在虚拟机规范中,§5.3. 创建和加载状态:
在运行时,类或接口不是由其名称单独决定的,而是由一对名称决定的:它的二进制名称(§4.2.1)及其定义类加载器。
特殊情况是通过新的 defineHiddenClass 方法。由于这些类无法通过其按名称定义的加载程序来解析,因此可以在不存在对隐藏类的引用时立即卸载该类。不能再装了。但是您可以使用相同的定义创建任意数量的相同隐藏类,因为它们不会相互干扰。

nle07wnf

nle07wnf2#

您是否尝试过使用单例设计模式创建持久对象?
单例是应用程序中唯一的一类对象,它是在第一次示例化时创建的。
只要应用程序正在运行,并且任何示例化都会返回当前示例或新示例(如果以前没有示例化过的话)。如果需要一个新示例,可以在singleton类上实现一个方法,该方法销毁当前示例并返回一个新示例。我使用单例来存储设置、访问和凭据管理。
下面是一篇关于单例的文章的链接:单例设计模式
如果您不运行多个线程,您可以使用本文中描述的方法1,这是我经常做的。但是,如果您运行多个线程,我建议您使用文章中提到的最后一个方法,因为它声称是最好的,尽管我没有测试它。

相关问题