问题:字符串常量池分配在什么内存区域? 方法区?永久区? 堆内存?
首先明晰几个概念:
方法区
- java虚拟机规范
的 运行时数据区
方法区
概念属于 java虚拟机规范
的 运行时数据区
的一部分. 运行时数据区包括: 程序计数器
、 java虚拟机栈
、 本地方法栈
、 java堆
、 方法区
. 其中, 方法区
跟 java堆
都是所有线程共享的数据区, 用于存放已被jvm加载的class信息、常量、static变量、JIT即时编译后的代码等这些数据.
永久区
- jvm实现
永久区又叫 PermGen
, 是jvm实现, 且只存在于jdk7和之前的版本;jdk8中已彻底移除PermGen,jdk8引入了一个新的内存区域: metaspace
;
然后再看下面程序的输出, 可确定java的版本 jdk6/7/8中的字符串分配的内存区域. 运行时指定 VM Options
参数 java -Xms20m -Xmx20m StringOOM
令程序内存过限:
import java.util.ArrayList; import java.util.List; public class StringOOM { static String base = "somethings"; public static void main(String[] args) { List<String> list = new ArrayList<>(); for (int i = 0; i < Integer.MAX_VALUE; i++) { String str = base + base; base = str; // 只是用来增长 /** intern 会把字符串发布到 字符串常量池中去 */ list.add(str.intern()); } } }
JDK8-在堆内存: OutOfMemoryError: Java heap space
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3332) at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448) at java.lang.StringBuilder.append(StringBuilder.java:136) at com.niewj.demo.lang.StringOOM.main(StringOOM.java:12) Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=8m; support was removed in 8.0 Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=8m; support was removed in 8.0
JDK7-在堆内存: OutOfMemoryError: Java heap space
PS C:/devs/java/jdk7/bin> ./java.exe -Xms20m -Xmx20m -XX:PermSize=8m -XX:MaxPermSize=8 StringOOM Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOfRange(Arrays.java:2694) at java.lang.String.<init>(String.java:203) at java.lang.StringBuilder.toString(StringBuilder.java:405) at StringOOM.main(StringOOM.java:10)
JDK6-在永久区: OutOfMemoryError: PermGen space
List<String> list = new ArrayList<>(); 无法编译, 必须写完整:List<String> list = new ArrayList<String>(); PS C:/devs/java/jdk6> ./bin/java.exe StringOOM Exception in thread "main" java.lang.OutOfMemoryError: PermGen space at java.lang.String.intern(Native Method) at StringOOM.main(StringOOM.java:12)
结论:
JDK6-在永久区: OutOfMemoryError: PermGen space
JDK7-在堆内存: OutOfMemoryError: Java heap space
JDK8-在堆内存: OutOfMemoryError: Java heap space
可见, JDK6
的jvm 对字符串常量池的内存区域的实现, 还在 永久区(PermGen)
; 而 JDK7/JDK8
就都是在 堆内存
中划分的内存了;