静态方法(实际上是所有方法)以及静态变量都存储在堆的PermGen 部分中,因为它们是反射数据的一部分(与类相关的数据,而不是与实例相关的数据)。从 Java 8 开始,PermGen 已被 MetaSpace 取代,并且根据 JEP 122,它只保存元数据,而静态字段存储在堆中。
请注意,这主要适用于 Oracle 的 Hotspot JVM 和其他基于它的。然而,并不是每个 JVM 都有像 Eclipse OpenJ9 这样的 PermGen 或 Metaspace。
更新说明:
请注意,只有变量及其技术值(基元或引用)存储在 PermGen 空间中。
如果您的静态变量是对对象的引用,则该对象本身存储在堆的正常部分(年轻/老一代或幸存者空间)中。这些对象(除非它们是类等内部对象)不存储在 PermGen 空间中。
例子:
static int i = 1; //the value 1 is stored in the PermGen section
static Object o = new SomeObject(); //the reference(pointer/memory address) is stored in the PermGen section, the object itself is not.
关于垃圾收集的一句话:
不要不依赖finalize(),因为它不能保证运行。完全由 JVM 来决定何时运行垃圾收集器以及收集什么,即使一个对象有资格进行垃圾收集。
当然,您可以将静态变量设置为 null,从而删除对堆上对象的引用,但这并不意味着垃圾收集器将收集它(即使没有更多参考)。
此外,finalize() 仅运行一次,因此您必须确保它不会引发异常或以其他方式阻止对象被收集。如果您因某些异常而停止最终确定,则不会在同一对象上再次调用 finalize()。
最后一点:如何存储代码、运行时数据等取决于所使用的 JVM,即 HotSpot 的存储方式可能与 JRockit 不同,甚至同一 JVM 的版本之间也可能不同.以上基于 Java 5 和 6 的 HotSpot(它们基本相同),因为在回答时我会说大多数人都使用这些 JVM。由于自 Java 8 起内存模型发生了重大变化,上述陈述可能不适用于 Java 8 HotSpot - 而且我没有检查 Java 7 HotSpot 的变化,所以我猜测以上该版本仍然适用,但我不确定。