You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

方法内声明的字符串变量内存分配位置:栈还是堆?

方法内字符串变量的内存分配详解

嘿,这俩问题其实是一套逻辑,我给你掰扯清楚~

1. 方法内部字符串变量的内存分配位置

方法里的字符串变量得分成两部分来看:

  • 引用变量本身:比如你写的String str;或者String str = "hello";里的str,这个变量是存在当前方法的**栈帧(Stack Frame)**里的,属于栈内存区域。等方法执行完毕,栈帧弹出,这个引用就会被销毁。
  • 字符串的实际对象内容:这部分的位置分两种场景:
    • 如果是字面量声明(比如String str = "hello";):JVM会先去字符串常量池(Java 7及之后,这个池是堆内存里的一块特殊区域)找有没有"hello",有的话直接让引用指向它;没有的话就先在常量池里创建这个字符串对象,再让引用指向它。
    • 如果是new关键字创建(比如String str = new String("hello");):JVM会先检查常量池里有没有"hello",没有就先在常量池创建,然后再在堆的普通区域生成一个新的字符串对象,最后让引用指向这个堆里的新对象。

2. 方法内字符串变量:栈还是堆?

这个问题得拆开来回答:

  • 变量的引用是在栈里的——因为它是方法内的局部变量,属于栈帧的局部变量表,方法一结束就跟着栈帧一起回收。
  • 字符串的实际对象实例(不管是常量池里的还是new出来的)都是在堆内存里的——哪怕是字符串常量池,从Java 7开始也已经移到堆里了,之前的方法区(永久代)现在改成元空间,但常量池还是归属堆区域。

举个代码例子更直观:

public void testStringMemory() {
    // str1是栈里的引用,指向堆中常量池里的"hi"
    String str1 = "hi";
    // str2是栈里的引用,指向堆普通区域的新String对象,该对象内部会指向常量池的"hi"
    String str2 = new String("hi");
}

执行这个方法时,str1和str2这两个引用都待在testStringMemory方法的栈帧里,而它们指向的字符串实体全在堆内存,只是所在的子区域不同而已。

额外补充个小细节:如果是字面量拼接(比如String str = "a" + "b";),编译器会直接优化成"ab",所以引用还是指向常量池里的对象;但如果是变量拼接(比如String str = str1 + str2;),会在堆的普通区域生成新对象(除非拼接结果刚好在常量池里)。


内容的提问来源于stack exchange,提问作者Sujeet Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:26:01