堆存对象实体,栈存方法调用和局部变量;new创建的对象在堆,基本类型和引用变量本身在栈;栈变量线程隔离、方法结束即销毁,堆对象可跨方法线程共享;stackoverflowerror调-xss,outofmemoryerror调-xms/-xmx;轻量短命数据用栈,复用长期数据用堆。

堆内存存对象实体,栈内存存方法调用和局部变量——这是最直接的区分原则。
看数据类型和创建方式
凡是由 new 创建的(包括数组、String 实例、ArrayList、自定义对象等),本体一定在堆中;
方法内定义的 基本类型(int、boolean、char 等)和 引用变量本身(如 String s、List list),都落在栈上。
注意:s = "abc" 中,如果字面量创建,字符串内容可能在字符串常量池(属方法区);s = new String("abc") 时,对象才真正在堆中。
看生命周期和共享范围
栈上的变量随方法结束立即消失,线程间完全隔离,不存在并发问题;
堆中的对象只要还有引用可达,就能跨方法、跨线程持续存在,所有线程都能访问同一份数据——这也意味着修改共享对象时需考虑同步。
看错误表现和调优参数
程序抛 StackOverflowError?大概率是递归过深或单个方法里定义了太多局部变量,可调大 -Xss(如 -Xss2m);
报 OutOfMemoryError: Java heap space?说明堆对象堆积过多或单个对象过大(比如读取超大文件到 byte[]),应检查对象引用链、调整 -Xms/-Xmx,并配合堆转储分析。
看性能和使用意图
临时计算、计数器、布尔开关这类轻量、短命的数据,放栈里最快最安全;
需要多处复用、长期持有、跨方法传递的数据结构(如缓存 Map、用户会话对象、配置实例),必须靠堆来承载;
频繁在堆上创建小对象(如循环中 new StringBuilder)虽合法,但会加重 GC 压力,可考虑复用或改用栈上等效操作(如用局部 char[] 替代短字符串拼接)。











