JVM(一)JVM内存模型

JVM内存模型

1. 程序计数器

程序计数器用来保存要执行的下一条字节码的行号,程序的分支、循环、跳转、异常处理等都依赖这个计数器完成。程序计数器是线程私有的,每个线程维护自己的程序计数器。程序计数器是唯一一个在JVM中没有规定任何OOME情况的区域。

2. Java虚拟机栈

线程私有的,每个线程都有一个自己的栈,用于存储局部变量表,就是操作系统中的栈概念。
当线程请求的栈深度大于虚拟机规定的最大深度时抛出 StackOverflowError 异常
当没有更多地内存空间来创建新的栈时,抛出 OutOfMemoryError异常

3. 本地方法栈

与虚拟机栈类似,区别在于本地方法栈为虚拟机用到的Native方法服务。在HotSpot虚拟机中,虚拟机栈和本地方法栈被合二为一。

4. Java堆

java堆是java虚拟机管理的内存中最大的一块,几乎所有的java类实例都存储在此内存区域。
1. Java堆被所有线程共享
2. 在虚拟机启动时创建
3. 此区域的唯一目的在于创建对象实例
4. 如果堆中没有更多的内存完成新的实例的创建并且不能再扩展堆的大小时,抛出 OutOfMemoryError 异常

5. 方法区

  1. 各个线程共享区域
  2. 用于存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
  3. 可以选择不垃圾回收
  4. 内存回收的主要目标是针对常量池的回收和对类型的卸载

运行时常量池

运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。


直接内存

除了上面的5大内存区域外,还有一个直接内存,直接内存不属于java虚拟机规范中规定的运行时数据区的一部分,通过某种方法可以直接分配java堆外内存供java对象引用,从而避免了从堆外内存到堆内内存的复制。如:NIO

小结

内存区 描述 特点 线程私有或公有 异常类型
程序计数器 程序计数器用来保存要执行的下一条字节码的行号,程序的分支、循环、跳转、异常处理等都依赖这个计数器完成。 内存区域小
2. 唯一一个没有规定OOMR的内存区域
私有
java虚拟机栈 虚拟机为每个方法创建一个虚拟机栈,存放有局部变量表、操作数栈、动态链接、方法出口信息 局部变量表在方法执行之前就被创建,其大小时确定的
2. 线程私有,生命周期和当前线程一样
私有 当栈深度超过虚拟机规定最大深度时抛出StackOverflowError
2. 当无法创建出新的栈时抛出OutOfMemoryError
本地方法栈 与虚拟机栈类似 为虚拟机执行本地方法服务 私有 同上
Java堆 用来存放几乎所有的类实例 JVM内存区中最大的一块
2. 几乎所有的类实例在此创建
3. 垃圾收集器主要管理的区域
公有 当没有更多空间创建新的实例且无法再扩展堆大小时抛出OutOfMemoryError异常
方法区 Java虚拟机规范中定义方法区是堆的一个逻辑部分。 永久代,方法区中存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等
2. 内存回收效率低
3.java虚拟机规范对方法区要求低,允许固定或可变大小,允许不垃圾回收
公有 无可用空间且无法扩展方法区大小时抛出OutOfMemoryError异常

对象的内存布局

对象的内存布局分为三部分:
1. 对象头
对象头一部分存储了对象自身的运行时数据,如hash码,锁状态标志能,另一部分存储了对象的类元数据指针,虚拟机据此判断对象是属于哪一个类的
2. 实例数据
即对象中的各种字段
3. 填充区域
HotSpot虚拟机规定对象的大小为8字节的整数倍,因此会存在填充区域(即占位符)来保证内存对齐

对象的访问定位

对象的访问定位有两种实现方式
1. 使用引用直接访问
此种方式下,java栈中的引用直接指向堆内存中的对象实例,优点是速度快,缺点是当垃圾回收导致堆中对象的地址发生变化时需要修改栈中的引用值
2. 使用引用指向句柄
这种方式下,java栈中的引用指向堆中的句柄池中的某个句柄,句柄指向真正的对象地址,优点是对象地址发生改变时不用改变引用值,只需改变句柄值,缺点是需要两次指针定位,速度较慢


猜你喜欢

转载自blog.csdn.net/wy11933/article/details/80099415