java程序的运行过程中,jvm所管理的内存将会包含以下几个运行时数据区域。
解释:可以看作当前线程所执行的字节码的行号指示器,在概念模型里,字节码解释器就是通过改变这个技术器的值来选取下一条需要执行的字节码指令。
- 线程私有
- 没有OOM
解释:用于描述java方法执行的内存模型。每个方法在执行的时候创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用2直至执行完成的过程,对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表存放编译期可知的:基本数据类型、对象的引用(大致可以看作一个指向对象地址的指针,非对象本身)。
- 线程私有
- 每个栈帧大小由参数 -Xss设置。默认为1M
- 太多次递归会导致StackOverflowError
- 栈帧太多会导致OOM
解释:与Java虚拟机栈相同只不过是本地方法使用,本地方法的意思是调用的方法会非Java程序。HotSpot虚拟机中将其与Java虚拟机栈合二为一。
解释:是JVM所管理的内存中最大的一块,几乎所有的对象实例都在这里分配内存。
可以处于物理上不连续的内存空间中。
Java堆还可分为:年轻代和老年代。
新生代还可分为:Eden区、From Survivor区、To Survivor区。
- 线程共享
- -Xms 启动时堆内存,-Xmx 最大堆内存,-Xmn 年轻代大小(推荐为整个堆的3/8)-XX:NewRatio 老年代与年轻代的比值 -XX:SurvivorRatio Edenq区与一个Survivor区的比值
- 可能分配出多个线程私有的分配缓冲区,以避免分配冲突。
- GC主要区域
- 超过最大堆内存会OOM
解释:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。
HotSpot以前将方法区使用永久代实现以便将Java堆的GC策略沿用,实际本质不一样,其他虚拟机不使用此实现方法。
JDK1.8中存放于元空间(Metaspace),元空间仍然与堆不相连。
常量池一共有三种:
字符串常量池
:在jdk1.8中位于Java堆中而不在方法区中了。Hotspot中是一个叫StringTable的类,本质是一个Hash表。存放字符串常量的引用和堆内字符串对象的引用。相同的只会存在一份,未声明的,只放结果(比如 直接拼接两个字符串);已经声明的,只放声明。
class常量池
:每个class文件都有一个常量池,用于存放编译器生成的各种字面量和符号引用。字面量包括文本字符串、八中基本类型的值、被声明为final的常量。符号引用包括类和方法的全限定名、字段的名称和描述符、方法的名称和描述符。是一种文件结构。
运行时时常量池
:class常量池被加载到内存之后的版本,字面量可以动态添加,符号引用可以被解析为直接引用。在元空间中
- 线程共享
- 很少GC 主要针对常量池的回收和类型的卸载。
- 使用本地内存
- -XX:MaxMetaspaceSize 最大元空间默认为无上限,会动态调整。-XX: MetaspaceSize 初始元空间大小。