静态变量的实际存储位置是什么?

38

静态变量被分配在程序执行的整个周期内,因此堆栈和堆对其不方便。那么这个变量在哪里呢?它应该从某个地方加载吗?


2
请参见:http://www.daniweb.com/software-development/java/threads/34695 - mnicky
7个回答

41
我们的内存分为三个部分:
  1. 栈段(Stack Segment) — 包含局部变量和引用变量(即保存在堆中的对象地址的变量)。

  2. 堆段(Heap Segment) — 包含运行时创建的所有对象,仅包括它们的属性(实例变量)。

  3. 代码段(Code Segment) — 加载时实际编译后的Java字节码所在的段。静态成员(变量或方法)被称为类成员,意味着它们存储在类(字节码)所在的Code Segment中。


6
这个回答得到了很多赞,但与https://dev59.com/UW865IYBdhLWcg3wYNZS#3849819相矛盾。 - ravindrab
3
Sourav,请问你能提供你的信息来源吗? - galeop
1
也许Sourav指的是C++? - flow2k

25

当一个类被加载时,静态字段会被初始化,当该类的类加载器被卸载时,它们会被丢弃。它们可以被清理,也可以在另一个类加载器中重复。

对于使用OSGi的应用程序等应用,静态变量不会在整个应用程序的生命周期内存在。它们可以被多次重新加载。

如何实现可能取决于JVM,但Sun/Oracle JVM创建了一个“对象”来保存类的静态字段。此对象可通过Unsafe类访问,也可用于检查此“对象”的字段。


9

静态变量在程序执行期间分配,因此堆栈和堆都不方便。

实际上,静态帧(即保存静态变量的帧)是从堆中分配的。

它们不一定存在于程序执行期间。例如,动态加载的类的静态帧可以在父类加载器、所有类和所有实例都不可达时被垃圾收集。


2
在JVM使用的五个内存区域中,静态字段在应用程序类加载器在准备和加载阶段加载类时在类区(PremGen的一部分)中分配内存。 如果字段是原始类型,则该值存储在类区中;如果它是对象类型(使用new运算符),则它存储在堆中,但引用被赋给类区中的静态字段变量。 当卸载类时,该静态字段的内存也可以由GC进行垃圾回收。
如果该字段还是final的,即静态final的话,它将保留在类区下的常量池中。

1

来自http://www.daniweb.com/software-development/java/threads/34695

静态变量的内存是在程序开始时分配的,分配在常规内存中,而不是堆栈(专门为程序设置的内存)。这样做的好处是使您的变量或过程完全恒定,并且您无法意外更改其值。缺点是直到程序终止,内存才会被释放。我从未听说过静态值占用的内存比常规声明的内存多,但它们的内存使用始终保持不变。


1
“完全常量”?你是想说 final 吗?而且内存直到结束才被释放,这不是一个缺点,这正是 static 的全部意义! - Oliver Charlesworth
1
@OliCharlesworth,他在谈论“static final”变量。与不需要这样做相比,被迫长时间使用更多内存是一个劣势。 - Pacerier

0

静态变量在与代码存储在同一内存段中提供内存,即类区域。它独立于堆栈或堆内存段,并在程序的完整持续期间保持可访问状态。


0

静态变量是整个类共享的变量,如果一个对象改变了变量的值,那么该类的每个对象的值都会被改变。


3
这个回答解释了静态变量是如何工作的,但没有解释内存管理的实际问题。 - David Torrey

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