JVM内存模型

131 阅读3分钟

说一下Java的内存模型?

根据JDK8规范,JVM运行时,内存共分为:

  • 虚拟机栈
  • 方法区(元空间)
  • 程序计数器
  • 本地方法栈

还有一部分内存叫 直接内存,属于操作系统的本地内存,也是可以操作的

程序计数器:用于存储当前线程正在执行的Java方法的JVM指令地址

  • 可以看作是当前线程所执行的字节码的行号指示器
  • 如果线程执行的是 Native 方法,计数器值为 null
  • 是虚拟机中唯一没有规定OutOfMemoryError情况的区域,同时也是线程私有的内存区域

Java虚拟机栈:每个线程都有自己的独立的Java虚拟机栈,生命周期与线程相同

  • 每个方法在执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息
  • 可能会抛出 StackOverflowErrorOutOfMemoryError 异常
  • 同时也是线程私有的内存区域

本地方法栈:与 Java 虚拟机栈类似,主要为虚拟机使用到的 Native 方法服务

  • 本地方法执行时也会创建栈帧
  • 样可能出现 StackOverflowErrorOutOfMemoryError 两种错误

Java堆:是JVM的最大一块内存区域,被所有线程共享

  • 在虚拟机启动时创建,用于存放对象实例
  • 从内存回收角度,堆被划分为新生代和老年代,新生代又分为 Eden 区和两个 Survivor 区(From Survivor 和 To Survivor)
  • 如果在堆中没有内存完成实例分配,并且堆也无法扩展时会抛出 OutOfMemoryError 异常

方法区(元空间):在 JDK 1.8 及以后的版本中,方法区被元空间取代

  • 用于存储已被虚拟机加载的类信息、常量、静态变量等数据
  • 是所有线程共享的内存区域
  • 方法区可以选择不实现垃圾收集,内存不足时会抛出 OutOfMemoryError 异常

运行时常量池:是方法区的一部分

  • 用于存放编译期生成的各种字面量和符号引用,具有动态性,运行时也可将新的常量放入池中
  • 当无法申请到足够内存时,会抛出 OutOfMemoryError 异常

直接内存:不属于JVM运行时数据区的一部分,通过 NIO 类引入,是一种堆外内存,可以显著提高 I/O 性能

  • 直接内存的使用受到本机总内存的限制
  • 若分配不当,可能导致 OutOfMemoryError 异常

方法区中的方法的执行过程?

当程序中通过某个对象或类直接调用某个方法时,主要通过以下几步:

  • 解析方法调用:JVM会根据方法的符号引用,找到实际的方法地址
  • 栈帧创建:在调用一个方法前,JVM会在当前线程的Java虚拟机栈中为该方法分配一个新的栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息
  • 执行方法:执行方法内的字节码指令,涉及的操作可能包括局部变量的读写、操作数栈的操作、跳转控制、对象创建、方法调用等
  • 返回处理:方法执行完毕后,可能会返回一个结果给调用者,并清理当前栈帧,恢复调用者的执行环境