数组变量arr存于栈中,仅保存引用地址;new int[5]分配的5个整数空间位于堆中,由JVM初始化为0;a和b可指向同一堆数组实现共享;逃逸分析可能将未逃逸数组优化至栈上分配。

Java里定义一个数组,比如 int[] arr = new int[5];,看似一行代码,背后却涉及栈与堆的明确分工和协同。理解这个过程,关键不是背概念,而是看清“谁存什么、存在哪、怎么连”。
数组变量名在栈上,数组本体在堆上
变量 arr 本身是个引用(即内存地址),它被当作局部变量,存放在当前方法的栈帧中——位置固定、生命周期短、随方法结束自动消失。而 new int[5] 真正申请的那块能装5个整数的连续空间,是在堆上动态分配的。堆负责长期持有数据实体,栈只负责“记个地址”。
这就像你写一张便签(栈)写着“我的文件夹在工位第三格”,而真正的文件夹(数组内容)是放在公共储物区(堆)里的。
数组元素默认值由堆初始化完成
基本类型数组(如 int[]、boolean[])创建时,JVM会**立即把整个数组区域清零或设为默认值**——这不是靠循环赋值,而是通过内存块置零指令(如 memset)高效完成。所以即使你没显式赋值,arr[0] 就已经是 0,这个值就实实在在存在于堆内存中。
注意:这个初始化动作发生在堆分配之后、构造返回之前,是JVM保障语义一致性的底层行为。
多个变量可指向同一堆数组
当你写:
int[] a = new int[3];<br>int[] b = a;
这时栈上有两个变量 a 和 b,它们存储的是**完全相同的堆地址**。修改 a[0] = 100,b[0] 马上变成 100——因为它们访问的是堆上同一块内存。
这种共享不增加堆开销,但需警惕意外修改。若需独立副本,必须显式调用 Arrays.copyOf() 或手动新建+复制。
逃逸分析可能改变分配位置(进阶提示)
现代JVM(如HotSpot)在开启逃逸分析后,若发现某个数组只在当前方法内使用、未被返回或传递给其他线程,就可能把它“栈上分配”——即整个数组结构(包括元素)都放在栈帧里,方法结束自动释放,彻底绕过堆和GC。
但这完全由JVM运行时决策,开发者无法强制;可通过 -XX:+DoEscapeAnalysis -XX:+PrintEscapeAnalysis 观察分析结果。日常编码仍应按“默认堆分配”来建模和设计。

















