Java8 的内存划分:https://blog.csdn.net/bruce128/article/details/79357870
运行时数据区域
线程私有:
- 虚拟机栈
- 本地方法栈
- 程序计数器
线程共享:
- 方法区(JDK8 已移除)
- 堆
JDK 1.8:
1、程序计数器
指向当前线程正在执行的字节码的行号,如果当前执行的是 Nativate 方法,则为 null
2、Java 虚拟机栈
每调用一个方法,就会往虚拟机栈中创建一个栈帧
- 栈帧:局部变量表、操作数栈、动态链接、方法出口信息
- 局部变量表:局部变量(八大原始类型、对象引用)、returnAddress(方法返回地址)
3、本地方法栈
用于调用 Nativate 方法
4、堆
年轻代 Young Gen
Eden + Survivor * 2 = 8 : 1 : 1
老年代 Old Gen
Young Gen : Old Gen = 1 : 2
字符串常量池
5、方法区
Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但它并不在堆中,所以有别名 Non-Heap
存储被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
所以,动态生成类的情况,容易造成永久代的溢出。比如 JSP
名称:
- 方法区:JVM 规范
- 永久代:JVM 规范的一种实现,JDK1.8 之前放在堆外的独立空间,在 GC 范围。
- HotSpot 才有 PermGen space,其他虚拟机没有
常量池:**
- 类文件中常量池(编译期):Class 文件中的常量池保存着各种编译期生成的各种字面量和符号引用
- 字符串常量池(编译期):存放各种字符串常量
- 运行时常量池(运行期):上述内存将在类加载后进入运行时常量池中存放
- 具备动态性,存储翻译后的直接引用、运行期间的新常量(String.intern())
- JDK1.7,从方法区迁移至堆
运行中常量池:JDK1.7 从方法区迁移至堆
永久代:JDK1.8 移除永久代,使用元空间 Metaspace 来实现方法区
- PermSize 和 MaxPermGen 已经无效
元空间 Metaspace:
- 元空间是对 JVM 规范中方法区的实现,使用 Native Memory
- -XX:MetaspaceSize,初始空间大小
- -XX:MaxMetaspaceSize,最大空间
Class 对象:堆
- Class 对象是类加载地最终产物
类的方法代码、变量名、方法名、访问权限、返回值等:方法区
Class 文件中的常量池:
如果变量名和字符串的值一样,那么常量池中只会保留一份字面量:
javap -verbose xxx.class
String.intern():检查字符串常量池中是否存在String并返回池里的字符串引用;若池中不存在,则将其加入池中,并返回其引用。
这样做主要是为了避免在堆中不断地创建新的字符串对象