运行时数据区
├── 线程私有区域
│ ├── 程序计数器
│ ├── Java虚拟机栈
│ └── 本地方法栈
└── 线程共享区域
├── Java堆(对象实例)
└── 方法区
└── 运行时常量池




| JDK版本 | 是否有永久代,字符串常量池放在哪里? | 方法区逻辑上规范,由哪些实际的部分实现的? |
|---|---|---|
| jdk1.6及之前 | 有永久代,运行时常量池(包括字符串常量池),静态变量存放在永久代上 | 这个时期方法区在HotSpot中是由永久代来实现的,以至于这个时期说方法区就是指永久代 |
| jdk1.7 | 有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆中; | 这个时期方法区在HotSpot中由永久代(类型信息、字段、方法、常量)和堆(字符串常量池、静态变量)共同实现 |
| jdk1.8及之后 | 取消永久代,类型信息、字段、方法、常量保存在本地内存的元空间,但字符串常量池、静态变量仍在堆中 | 这个时期方法区在HotSpot中由本地内存的元空间(类型信息、字段、方法、常量)和堆(字符串常量池、静态变量)共同实现 |
http://openjdk.java.net/jeps/122
Remove the permanent generation from the Hotspot JVM and thus the need to tune the size of the permanent generation.
从 Hotspot JVM 中移除永久代,从而无需调整永久代的大小。
为永久代设置空间大小是很难确定的。
在某些场景下,如果动态加载类过多,容易产生 Perm 区的 OOM。如果某个实际 Web 工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现 OOM。而元空间和永久代最大的区别在于,元空间不在虚拟机中,而是使用本地内存,所以默认情况下,元空间的大小仅受本地内存限制
对永久代进行调优较困难
运行时常量池是 ** 方法区(JDK8 及以后为元空间)** 的一部分,是 Class 文件中 “常量池表” 的运行时表示形式。
String.intern()方法动态添加的字符串常量,或其他类型的动态常量(如包装类的valueOf()缓存)。