Java的JVM内存模型

169 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情

一、什么是JVM

Java虚拟机本质上就是⼀个程序,当它在命令⾏上启动的时候,就开始执⾏保存在某字节码⽂件中的指令。Java语⾔的可移植性正是建⽴在Java虚拟机的基础上。任何平台只要装有针对于该平台的Java虚拟机,字节码⽂件(.class)就可以在该平台上运⾏。这就是“⼀次编译,多次运⾏”。

二、JVM的体系

JVM主要分为五⼤体系:

  • 类装载器⼦系统
  • 运⾏时数据区
  • 执⾏引擎
  • 本地⽅法接⼝
  • 垃圾收集模块

其中运⾏时数据区就是,java虚拟机所管理的内存模型,分为五大区域。分别是:

  • 程序计数器
  • 本地⽅法栈
  • 虚拟机栈
  • ⽅法区

image.png

三、线程私有——程序计数器

程序计数器是⼀块较⼩的内存空间;它是线程私有的,可以看做是当前线程所执⾏的字节码的⾏号指示器,在java虚拟机的概念模型⾥,字节码解释器⼯作时就是通过改变这个计数器的值来取下⼀条需要执⾏的字节码指令。每条线程都需要⼀个单独的程序计数器,各线程之间的计数互不影响,独⽴存储,所以这类内存区域叫 线程私有内存

这个区域是java虚拟机中唯⼀⼀个不会出现OOM情况的区域

四、线程私有——虚拟机栈

属于线程私有⽣命周期与线程相同,随线程⽽⽣,随线程⽽灭;java虚拟机栈描述的是java⽅法执⾏的线程内存模型:每个⽅法被执⾏的时候,java虚拟机都会同步创建⼀个栈帧(Stack Frame),栈帧会存储局部变量表、操作数栈、动态连接、⽅法出⼝、附加信息;每⼀个⽅法被调⽤直⾄执⾏完毕的过程,就是对应着⼀个栈帧在虚拟机栈中从⼊栈到出栈的过程。

五、线程私有——本地方法栈

本地⽅法栈⽤于管理本地⽅法的调⽤,Java虚拟机栈⽤于管理Java⽅法的调⽤;本地⽅法栈,也是线程私有的;允许被实现成固定或者是可动态拓展的内存⼤⼩,本地⽅法是使⽤C语⾔实现的;并不是所有的JVM都⽀持本地⽅法。因为Java虚拟机规范并没有明确要求本地⽅法栈的使⽤语⾔、具体实现⽅式、数据结构等。如果JVM产品不打算⽀持native⽅法,也可以⽆需实现本地⽅法栈;在hotSpot JVM中,直接将本地⽅法栈和虚拟机栈合⼆为⼀。

六、线程共享——方法区(Method Area)

属于所有线程共享数据;⽅法区在JVM启动时就会被创建,并且它的实际的物理内存空间中和Java堆区⼀样都可以是不连续的;⽅法区的⼤⼩,跟堆空间⼀样,可以选择固定⼤⼩或者可拓展⽅法区的⼤⼩决定了系统可以保存多少个类。

⽤于存储已经被虚拟机加载的类型信息:常量、静态变量、即时编译器编译后的代码缓存、运⾏时常量池等数据。

七、线程共享——Java堆

堆 Heap 是虚拟机中占⽤内存最⼤的⼀块;堆是线程共享的,在虚拟机启动的时候创建,此区域存放的是对象实例,“⼏乎” 所有的对象实⼒都在这⾥分配内存。

堆是垃圾收集管理的内存区域,因此它也被称为GC堆;java堆既可以实现成固定⼤⼩的,也可以是可扩展的,不过当前主流的java虚拟机都是按照可扩展来实现的;堆的⼤⼩可以通过Xmx 和Xms 设定。假如java堆中没有完成实例分配,并且堆也不能再扩展时,java虚拟机就会抛出OOM。

image.png