局部变量存栈、实例变量存堆、静态变量存方法区(jdk 8+为元空间);因栈支持快进快出与线程隔离,堆承载对象生命周期,方法区管理类级别共享数据。

局部变量存在栈里,成员变量存在堆或方法区——这是最直接的回答。关键不在“在哪”,而在于“为什么这样设计”。
局部变量存栈:快进快出,符合方法调用逻辑
每次调用方法,JVM 就在虚拟机栈中开辟一个栈帧(Stack Frame),里面放参数、局部变量、操作数栈等。方法执行完,栈帧弹出,局部变量自动销毁。
- 栈内存分配和回收极快,不需要 GC 参与
- 天然支持多线程:每个线程有独立栈,局部变量互不干扰
- 比如 int count = 5;、String temp = "abc"; 都在当前栈帧里,出了方法就没了
实例变量存堆:跟着对象走,生命周期由对象决定
只要对象还活着(没被 GC 回收),它的所有实例变量就一直存在堆中。哪怕方法已结束,只要对象引用还在,变量就还在。
- 堆是所有线程共享的内存区域
- 实例变量是对象状态的一部分,必须和对象共存亡
- 例如 new Student() 创建的对象,name、age 这些实例变量都随它一起在堆中分配
类变量(static 成员变量)存在方法区:属于类本身,只有一份
类加载时,static 变量就被初始化并存入方法区(JDK 8+ 是元空间)。它不依赖任何对象,整个 JVM 中该类只有一个副本。
- 被所有实例共享,修改一处,全部可见
- 生命周期从类加载开始,到类卸载结束(通常贯穿整个应用运行期)
- 比如 public static final String VERSION = "1.0"; 就在这里,不是堆也不是栈
一个小陷阱:别把“存储位置”和“值的内容”搞混
比如局部变量 String s = new String("hello");
- s 这个引用变量本身在栈中
- 但 new 出来的字符串对象,实际存在堆中
- 而字符串字面量 "hello" 在字符串常量池(也属于方法区)
所以不能只说“String 存哪”,得看说的是引用,还是它指向的对象。











