Java中的静态方法和静态变量存储在哪里?

145

例如:

class A {
    static int i=0;
    static int j;

   static void method() {
       // static k=0; can't use static for local variables only final is permitted
       // static int L;
    }
}

这些变量会被存储在Java中的堆内存还是栈内存中?它们是如何存储的?

3
Oracle官方网站上非常有用的链接,可以帮助理解垃圾回收:http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html。 - Arnav Joshi
11个回答

180

静态方法(实际上所有方法)以及静态变量与反射数据相关,因此它们都存储在堆的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 过程,则 finalize() 方法不会再次在同一对象上被调用。

最后注意:代码、运行时数据等的存储方式取决于使用的 JVM,例如 HotSpot 和 JRockit 可能会有所不同,甚至同一 JVM 的不同版本也可能不同。以上内容基于 Java 5 和 6 的 HotSpot 实现,因为在回答问题时,我认为大多数人都使用这些 JVM 版本。由于 Java 8 中内存模型的重大变化,以上内容可能不适用于 Java 8 的 HotSpot 实现,而我也没有检查 Java 7 HotSpot 的更改,因此我只能猜测以上内容在该版本中仍然适用,但我不确定。


1
哦,你确定静态变量吗?据我所知,PermGen仅存储定义而不是实际值。 - Amir Raminfar
2
@Amir 我相当确定变量本身被存储在permgen空间中,任何引用的对象很可能都会被分配到堆上。这里可能会增加一些信息:https://dev59.com/ZlDTa4cB1Zd3GeqPLr2O - Thomas
1
啊,是的,变量定义存储在PermGen中。但是值将存储在堆中。您的回答暗示该值也存储在PermGen中。 - Amir Raminfar
2
@Nav 默认情况下,堆的所有部分都不会被垃圾回收,有时类和静态变量也无法被回收,因为类加载器仍然对它们有引用。此外,您不应该依赖垃圾收集器运行,因为这完全取决于JVM(它决定何时运行和收集什么,您只能提供提示,例如“我想让您现在运行gc” :))。 - Thomas
1
PermGen不一定是堆区的一部分。只是想要明确指出。 - stdout
显示剩余16条评论

41

Java8之前:

静态变量存储在永久代空间(也称为方法区)。

PermGen Space也被称为方法区

永久代空间用于存储3个东西:

  1. 类级数据(元数据)
  2. 字符串池
  3. 静态变量

从Java8开始

静态变量存储在堆内存中。自Java 8以来,永久代空间已被删除,并引入了一个名为MetaSpace的新空间,它不再是先前Permgen Space的一部分。 Meta-Space存在于本地内存中(操作系统提供给特定应用程序供其自身使用的内存),现在仅存储类元数据。

字符串池和静态变量移动到堆内存本身中。

有关官方信息,请参阅:JEP122:删除永久性Gen Space


当你在Java8及以上版本中谈论静态变量的“堆本身”时,它确切地位于OldGen吗? - Ewoks

29

类变量(静态变量)存储在与该类相关的Class对象的一部分中。此Class对象只能由JVM创建,并存储在permanent generation中。

有些人回答说它存储在非堆区域,称为Method Area。即使这个回答也不是错的。显然,Permgen区域是否属于堆的一部分是一个有争议的话题。在我看来,我们在JVM参数中提供了堆空间和permgen空间。因此,把它们当作不同的部分来处理是一个好的假设。

另一种看待它的方式

JVM内存管理器在运行时创建内存池。内存池可以属于堆内存或非堆内存。运行时常量池是一个每个类或接口运行时表示类文件中constant_pool表的表示形式。每个运行时常量池都从Java虚拟机的方法区分配,静态变量存储在此Method Area中。 此外,这个非堆实际上就是perm gen区域。实际上,Method Area是Permgen区域的一部分。(参考

enter image description here


方法区不是内存的PermGen部分的子集吗?为什么您将方法区显示为非堆内存的一部分,而我认为它们(包括PermGen和方法(类)区域)是JVM较大堆区域的一部分? - Kaveesh Kanwal
阅读最后一行 - 此外,这个非堆栈区实际上就是永久代区域。实际上,方法区是永久代的一部分。 - Aniket Thakur
1
@AniketThakur,你把方法区显示为非堆内存的一部分,但根据Oracle文档,在这里https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.4中提到,方法区在逻辑上是堆的一部分。 - Karan

17

这是一个有简单答案和冗长答案的问题。

简单的答案是堆(heap)。类和所有适用于类的数据(不是实例数据)存储在堆的永久代(Permanent Generation)部分。

冗长的答案已经在Stack Overflow上:

有一个关于JVM内存和垃圾回收的详细描述,以及一个更简洁地讨论它的答案。


3
没问题!如果你觉得那些人有用的话,请别忘了为他们点赞。 - Vasiliy Sharapov

10

它存储在类定义所引用的堆内存中。如果你仔细想一下,它与栈无关,因为没有作用域。


不正确。静态字段本身不存储在堆中。 - devoured elysium

5
除了Thomas的答案,静态变量存储在非堆区域中,称为方法区。

4

由于静态变量是类级别的变量,它们会存储堆内存中的“永久代”。 请查看这个链接以获取有关JVM的更多详细信息。希望这对您有帮助。


1
在现实世界或项目中,我们需要提前确定需求并在类内创建变量和方法。根据需求,我们需要决定是否需要创建以下内容:
1. 局部变量(在块或方法构造函数内创建并访问); 2. 静态变量; 3. 实例变量(每个对象都有自己的副本)。
=>2. 静态关键字将与变量一起使用,该变量将在整个类中保持不变,适用于所有对象。
例如,在Selenium中:我们将WebDriver声明为静态=>因此,我们不需要为每个测试用例再次创建WebDriver。

Static Webdriver driver

(但是在并行执行时会导致问题,但这是另一种情况);
现实场景=>如果印度是一个类,则国旗和货币对于每个印度人都是相同的,因此我们可以将它们视为静态。
另一个例子:我们总是将实用方法声明为静态,因为它将在不同的测试用例中使用。 静态存储在CMA(PreGen space)= PreGen(固定内存),在Java8之后更改为Metaspace,因为现在它正在动态增长。

1

静态变量存储在堆中


8
静态变量存储在内存的PermGen空间中,它们的值存储在堆中。 - Akash5288

1

当我们创建静态变量或方法时,它们存储在堆的一个特殊区域中:PermGen(永久代),其中包含所有适用于类(非实例数据)的数据。

从Java 8开始,PermGen变成了Metaspace。

不同之处在于,Metaspace是一个自动增长的空间,而PermGen具有固定的最大大小,并且此空间在所有实例之间共享。此外,Metaspace是本地内存的一部分,而不是JVM内存。

您可以查看this以获取更多详细信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接