Java虚拟机内存模型

为什么要了解Java虚拟机

Java是目前用户最多,使用最广泛的软件开发语言之一。

Java的优点

Java在虚拟机层面隐藏了底层技术的复杂性以及机器和操作系统的差异。开发只需要关注具体业务逻辑。

然而凡事都有两面性。

  • 某些领域,对程序的性能,稳定性和可拓展性方面都有极高的要求。程序可能10个人使用时完全正常,但是1000个人同时使用就会缓慢、死锁,设置崩溃。即使提升硬件也无法等比例的提升运作性能和并发能力,甚至完全没有任何改善。
  • 这里有Java虚拟机的原因,为了达到平台一致性的目的,牺牲了一些与硬件相关的性能特性。如果程序员不了解虚拟机的一些技术特性的运行原理,就无法写出最适合虚拟机运行和自由化的代码。

其实,虚拟机是可以调优的。而且调优是三类人员必备的

  • 使用Java技术体系中的中、高级开发人员。
  • 系统调优师
  • 系统架构师

Java虚拟机运行时数据区

Java虚拟机内存模型_第1张图片

程序计数器(Program Counter Register)

  • 它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器。
  • 每一条JVM线程都有自己的PC寄存器,各条线程之间互不影响,独立存储,这类内存区域被称为“线程私有”内存
  • 在任意时刻,一条JVM线程只会执行一个方法的代码。该方法称为该线程的当前方法(Current Method)
  • 如果该方法是java方法,那PC寄存器保存JVM正在执行的字节码指令的地址
  • 如果该方法是native,那PC寄存器的值是undefined。
  • 此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

Java虚拟机栈(Java Virtual Machine Stack)

  • 与PC寄存器一样,Java虚拟机栈也是线程私有的。每一个JVM线程都有自己的java虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同。
  • 虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
  • 局部变量表所需的内存空间在编译期间完成分配。
  • 如果县城请求的栈深度大于虚拟机允许的最大深度,将抛出 StackOverflowError异常。
  • 当前大部分的JVM都可以动态扩展,但是在尝试扩展时无法申请到足够的内存时,将抛出OutOfMemoryError。

本地方法栈(Native Method Stack)

  • 本地方法栈与虚拟机栈作用相似,后者为虚拟机执行Java方法服务,而前者为虚拟机用到的Native方法服务。
  • 本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。

Java堆(Java Heap)

  • 虚拟机管理的内存中最大的一块,同时也是被所有线程所共享的,它在虚拟机启动时创建。

  • 此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都要在这里分配内存。

  • 现代收集器基本都采用分代收集:Java堆还可以分为:新生代,老生代,永生代。其中新生代又分为Eden区,From Survivor区,To Survivor区。

  • Java堆的容量可以是固定大小,也可以随着需求动态扩展(-Xms和-Xmx),并在不需要过多空间时自动收缩。

  • Java堆所使用的内存不需要保证是物理连续的,只要逻辑上是连续的即可。

  • JVM实现应当提供给程序员调节Java 堆初始容量的手段,对于可动态扩展和收缩的堆来说,则应当提供调节其最大和最小容量的手段。

  • 如果堆中没有内存完成实例分配并且堆也无法扩展,就会抛OutOfMemoryError。

方法区(Method Area)

  • 跟堆一样是被各个线程共享的内存区域,用于存储以被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然这个区域被虚拟机规范把方法区描述为堆的一个逻辑部分,但是它的别名叫非堆,用来与堆做一下区别。

  • 方法区在虚拟机启动的时候创建。

  • 方法区的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。

  • 方法区在实际内存空间中可以是不连续的。

  • 当方法区无法满足内存分配需求时就会抛OutOfMemoryError。

你可能感兴趣的:(Java虚拟机内存模型)