例如:
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中的堆内存还是栈内存中?它们是如何存储的?
例如:
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;
}
}
静态方法(实际上所有方法)以及静态变量与反射数据相关,因此它们都存储在堆的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 的更改,因此我只能猜测以上内容在该版本中仍然适用,但我不确定。
Java8之前:
静态变量存储在永久代空间(也称为方法区)。
永久代空间用于存储3个东西:
从Java8开始
静态变量存储在堆内存中。自Java 8以来,永久代空间已被删除,并引入了一个名为MetaSpace的新空间,它不再是先前Permgen Space的一部分。 Meta-Space存在于本地内存中(操作系统提供给特定应用程序供其自身使用的内存),现在仅存储类元数据。
字符串池和静态变量移动到堆内存本身中。
有关官方信息,请参阅:JEP122:删除永久性Gen Space
类变量(静态变量)存储在与该类相关的Class对象
的一部分中。此Class对象只能由JVM创建,并存储在permanent generation
中。
有些人回答说它存储在非堆区域,称为Method Area
。即使这个回答也不是错的。显然,Permgen区域是否属于堆的一部分是一个有争议的话题。在我看来,我们在JVM参数中提供了堆空间和permgen空间。因此,把它们当作不同的部分来处理是一个好的假设。
另一种看待它的方式
JVM内存管理器在运行时创建内存池。内存池可以属于堆内存或非堆内存。运行时常量池是一个每个类或接口运行时表示类文件中constant_pool表的表示形式。每个运行时常量池都从Java虚拟机的方法区分配,静态变量存储在此Method Area中。 此外,这个非堆实际上就是perm gen区域。实际上,Method Area是Permgen区域的一部分。(参考)
此外,这个非堆栈区实际上就是永久代区域。实际上,方法区是永久代的一部分。
- Aniket Thakur这是一个有简单答案和冗长答案的问题。
简单的答案是堆(heap)。类和所有适用于类的数据(不是实例数据)存储在堆的永久代(Permanent Generation)部分。
冗长的答案已经在Stack Overflow上:
有一个关于JVM内存和垃圾回收的详细描述,以及一个更简洁地讨论它的答案。
它存储在类定义所引用的堆内存中。如果你仔细想一下,它与栈无关,因为没有作用域。
(但是在并行执行时会导致问题,但这是另一种情况);
Static Webdriver driver
静态变量存储在堆中
当我们创建静态变量或方法时,它们存储在堆的一个特殊区域中:PermGen(永久代),其中包含所有适用于类(非实例数据)的数据。
从Java 8开始,PermGen变成了Metaspace。
不同之处在于,Metaspace是一个自动增长的空间,而PermGen具有固定的最大大小,并且此空间在所有实例之间共享。此外,Metaspace是本地内存的一部分,而不是JVM内存。
您可以查看this以获取更多详细信息。