【Java】JVM虚拟机内存模型

一、jvm概述

java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

1. jvm两种类型

  • client:GUI等java程序的运行。
  • server:大型后台服务的运行。(重型虚拟机)

   * 两者的区别在于: server模式下,jvm启动较慢,但运行效率远远高于client模式。

* jdk在初始安装时就会选择安装哪种类型,当计算机CPU最少两颗,同时内存最少为2GB时就会切换到server。
* 也可以手动对jvm类型进行更改,但是64位的目前只能使用server模式。
  配置文件位置:[32bit]$JAVA_HOME/jre/lib/i386/jvm.cfg  |  [64bit]$JAVA_HOME/jre/lib/amd64/jvm.cfg
  -server KNOWN
  -client KNOWN
  只需要切换两者的顺序即可,但要注意文件中不能有空行,结束必须有一个空行,否则会出错。

jvm运行效率对比图

2. HotSpot

  • HotSpot:热点代码探测技术,可以通过执行计数器找出最具有编译价值的代码,然后通知JIT编译器(即时编译系统)以方法为单位进行编译。如果一个方法频繁调用,或方法中有效循环次数很多,将会触发标准编译和OSR(栈上替换)编译动作。通过编译器与解释器恰当的协同工作,可以在最优化的程序响应时间与最佳执行性能中取得平衡,而且无需等待本地代码输出才能执行程序。JDK1.5版本以后才开始使用这种策略。
  • 即时编译JIT(Just in Time)的时间压力也相对减小,这样有助于引入更多的代码优化技术,输出质量更高的本地代码。

二、jvm虚拟内存模型

JVM(Java Virtual Machine)包括运行时数据区(Runtime Data Areas)、执行引擎和本地方法库。下图是运行时数据区的图解(图片来源于简书)。
在这里插入图片描述

  • 方法区(Method Area):方法区和堆一样,属于被所有线程内存共享的区域,有时候我们也会称方法区为非堆,用于存储已经被Java虚拟机加载了的类信息、常量、静态变量、以及即时编译器编译后的代码等数据。

  • 运行时常量池(Runtime Constant Pool):是方法区的一部分。类文件的信息包括:类版本、字段、方法、接口等描述信息之外,还包括常量池、用于存放编译时生成的字面量和符号引用,老版JDK中,把运行时常量池也叫永久带,不会被GC所回收,JDK1.7之后,HotSpot虚拟机把字符串常量池从永久代中移出(String.interns()–>字符串常量池中如果包含这个对象,则返回池中的对象),可以通过改变启动参数值-XX:PermSize和-XX:MaxPermSize设置方法区的内存大小。

  • 堆(Heap):堆是占用Java内存最大的一块,通常堆会占到整个虚拟机内存的80%-85%,主要存放的是Java对象,被所有线程共享。在Java虚拟机启动时就会被创建,几乎所有的对象实例都会被存放在堆中,随着JIT编译器技术的发展和逃逸分析技术的逐渐成熟,有些对象会被分配到其他的内存区域。另外,这块内存区域是Java虚拟机规范中唯一一块没有OutOfMemoryError的区域。 堆是GC(Garbage Collection)的重点回收对象,现在收集器多采用分代回收的方法,所以堆中的Java对象会进行分代,包括新生代(Young Generation)、老年代(Old Generation),老年代。新生代又分成Eden区、From Survivor区和To survivor区。 堆可以是固定的内存大小区域,也可以进行扩展。当堆无法分配对象实例并且无法进行扩展的时候,就会抛出OutOfMemoryError异常。

  • 虚拟机栈(JVM Stacks):每个方法被执行的时候都会创建一个栈帧用于存储局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用的过程就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。其中局部变量表存放的是编译器可知的基本数据类型和return Address类型。long和double类型会占用两个slot空间(局部变量空间),其余数据类型只占用1个,局部变量表内存空间在编译期间完成分配,运行期间,局部变量表的内存空间不会再发生改变。

  • 本地方法栈(Native Method Stacks):和虚拟机栈所发挥的作用很类似,区别不同的是,本地方法栈执行的Java的本地方法(native)方法,而虚拟机栈执行的是Java方法(编译成字节码的方法)。有时候虚拟机会将这两个栈合二为一,本地方法栈和虚拟机栈都会出现StackOverFlowError(超过栈深度)和OutOfMemoryError(动态扩展内存不足)。

  • 程序计数器(Program Counter Register):是一块很小的内存区域,线程私有的,记录的是线程执行的字节码的行号。分支、循环、跳转、异常、线程恢复都需要依赖于程序计数器。当执行的程序是Java的底层(native)方法时,程序计数器为空,如果执行的是Java方法,计数器记录的是虚拟机字节码指令的地址。这块内存区域是Java虚拟机规范中唯一一块没有OutOfMemoryError的区域。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章