jvm内存模型
一、简要模型
- 在jdk1.8之前
- jdk1.8之后
- 两个版本之间的区别
- 元数据区取代了永久代的方法区。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元数据空间并不在虚拟机中,而是使用本地内存。
二、各区域详细介绍
1. 程序计数器
- 一块较小的内存空间, 是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的 程序计数器,这类内存也称为“线程私有”的内存。
- 正在执行 java 方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如 果还是Native方法,则为空。
- 这个内存区域是唯一一个在虚拟机中没有规定任何OutOfMemoryError情况的区域。
2. java虚拟机栈
- 是描述java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame) 用于存储局部变量表、操作数栈、动态链接、方法出口等信息
- 每一个方法从调用直至执行完成 的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程
- 栈帧随着方法调用而创建,随着方法结束而销毁——无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异 常)都算作方法结束。
3.本地方法栈
- 本地方法区和Java Stack作用类似, 区别是虚拟机栈为执行Java方法服务, 而本地方法栈则为 Native方法服务
4.堆
- 是被线程共享的一块内存区域,创建的对象和数组以及类的静态变量都保存在 Java 堆内存中,也是垃圾收集器进行 垃圾收集的重要的内存区域。由于现代VM采用分代收集算法, 因此Java堆从GC的角度还可以 细分为: 新生代( Eden 区 、 From Survivor 区 和 To Survivor 区 )和老年代。
5.常量池
- 1.7把字符串常量池从永久代中剥离出来,存放在堆空间中。原因是存放在永久方法区的常量池会出现性能问题和内存溢出
- 用于存放编译期生成的各种字面量和符号引用
6.元数据区
- 元数据区和永久代本质上都是方法区的实现。方法区存放虚拟机加载的类信息,静态变量,常量等数据。
- 大部分类源数据都在本地内存中分配(MaxMetaspaceSize)参数可以限制本地内存分配给元数据区的大小
- 实时监控和调整空间有利于垃圾回收的频率和减少延时。
三、String.inter()方法
- 这个方法是一个 native 的方法,但注释写的非常明了。“如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回”。