“this”引用存于虚拟机栈局部变量表第0号槽位,指向堆中对象;static变量存于方法区(jdk8+为元空间),属类级别且唯一。二者因生命周期、作用域及归属对象不同而存放位置不同。

“this”引用和static变量在JVM内存中存放位置不同,根本原因在于它们的生命周期、作用域和归属对象不同——this属于实例方法调用时的当前对象上下文,而static变量属于类本身,与任何具体实例无关。
“this”引用存于虚拟机栈的局部变量表中
每当一个实例方法被调用,JVM会为该方法创建一个栈帧。这个栈帧的局部变量表第0号槽位(slot 0)固定存放当前对象的引用,也就是“this”。它不是对象本身,只是一个指向堆中对象地址的引用值。
- 例如:调用 obj.doSomething() 时,“obj”这个引用被压入当前线程的栈帧中,作为this使用
- this只在方法执行期间存在,方法退出,栈帧弹出,this引用随之消失
- 基本类型、对象引用、returnAddress等都放在栈帧的局部变量表里,栈是线程私有的、快速分配释放的区域
static变量存于方法区(JDK8+为元空间)的类元数据结构中
static修饰的变量属于类级别,随类加载而初始化,整个JVM中只有一份副本。它不依赖对象存在,即使没有new出任何实例,static变量也已就位。
- JDK7及以前:static变量存于永久代(PermGen)
- JDK8开始:永久代被移除,static变量(含类信息、常量池、静态字段)统一存入元空间(Metaspace),物理上位于本地内存(Native Memory)
- 注意:static基本类型变量(如 static int x = 5)值直接存于元空间;static引用类型变量(如 static List list)则存储的是指向堆中对象的引用,对象本体仍在堆中
堆中对象本身与两者的关系
通过new创建的对象实例,无论是否被this引用,其实际数据(包括非static成员变量)都存放在堆中。堆是线程共享、GC主要管理的区域。
- 每个对象在堆中都有自己的内存布局:对象头 + 实例数据 + 对齐填充
- this引用只是栈中一个“指针”,指向堆中某个对象的起始地址
- static变量不指向堆中的某个特定对象,而是由类加载器维护,与Class对象强绑定
一个直观对比示例
假设定义如下类:
class Demo {static int count = 1;
int value = 2;
void print() { System.out.println(this.value); }
}
- 类加载时,count=1 存入元空间(方法区)
- 执行 new Demo() → 对象实例存于堆,value=2 是该对象的一部分
- 调用 obj.print() → 当前线程栈中生成栈帧,slot 0 存 this(即obj的地址),print方法内访问 this.value 实际是从堆中读取











