Java的String常量池位于何处,堆还是堆栈?
我知道 JVM 用于处理字符串文本的常量池和字符串常量池的概念。但是我不知道JVM使用哪种类型的内存来存储字符串常量文本。堆栈还是堆?由于它是一个不与任何实例关联的文字,因此我认为它将存储在堆栈中。但是,如果它没有被任何实例引用,则文本必须由GC run收集(如果我错了,请纠正我),那么如果它存储在堆栈中,如何处理它?
我知道 JVM 用于处理字符串文本的常量池和字符串常量池的概念。但是我不知道JVM使用哪种类型的内存来存储字符串常量文本。堆栈还是堆?由于它是一个不与任何实例关联的文字,因此我认为它将存储在堆栈中。但是,如果它没有被任何实例引用,则文本必须由GC run收集(如果我错了,请纠正我),那么如果它存储在堆栈中,如何处理它?
从技术上讲,答案也不是。根据 Java 虚拟机规范,用于存储字符串文本的区域位于运行时常量池中。运行时常量池内存区域是按类或按接口分配的,因此它根本不绑定到任何对象实例。运行时常量池是方法区域的子集,它“存储每个类的结构,如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括类和实例初始化以及接口类型初始化中使用的特殊方法”。VM 规范指出,尽管方法区域在逻辑上是堆的一部分,但它并不规定在方法区域中分配的内存受垃圾回收或与分配给堆的正常数据结构关联的其他行为的影响。
正如这个答案所解释的,字符串池的确切位置没有指定,并且可能因 JVM 实现而异。
有趣的是,在Java 7之前,池位于热点JVM上堆的permgen空间中,但自Java 7以来,它已被移动到堆的主要部分:
区域:热点
概要:在 JDK 7 中,暂存字符串不再在 Java 堆的永久生成中分配,而是在 Java 堆的主要部分(称为年轻和老一代)以及应用程序创建的其他对象中分配。此更改将导致驻留在主 Java 堆中的数据更多,而永久生成中的数据较少,因此可能需要调整堆大小。由于这种变化,大多数应用程序在堆使用方面只会看到相对较小的差异,但是加载许多类或大量使用String.intern()方法的大型应用程序将看到更显着的差异。RFE: 6962931
在Java 8 Hotspot中,永久生成已被完全删除。