JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是在操作系统之上重新虚拟出来的一套系统,是Java程序(不仅仅是java程序,只要是符合JVM字节码规范的程序,比如Kotlin、 Groovy、 Scala这些语言的程序也是可以运行的)的运行环境,负责将字节码转换为机器码并执行。
JVM的作用
3.1 write once,run anywhere(一次编写,到处运行)
学过java的同学应该都听过吧,Java号称一次编写,到处运行,其实真正实现到处运行的就是JVM,JVM提供的字节码程序运行环境屏蔽了不同操作系统(windows、macOS、linux系统等)的差异,由JVM去适配各个操作系统的接口,也就是说不同的操作系统有不同的JVM实现,从而实现java语言跨平台运行的能力,达到一次编写到处运行的效果。
JVM提供的是程序的运行环境,它并不关心你用的是什么语言,只要最终编译后的字节码符合JVM规范,它都可以运行,这样就使得代码和运行环境分开了,同一份代码编译后就可以在不同的操作系统上由对应的JVM去运行。开发的时候我们安装的是JDK,JDK包含了开发的一些工具集,也包含了JRE(Java Runtime Environment,java程序运行环境),这个JRE包含了JVM,而生产上一般只需要安装JRE去运行我们编译好的class字节码文件即可。
3.2 自动内存管理
C和C++语言都是通过手动操作主动去申请内存和释放内存,虽然灵活但是稍不注意没有释放就可能导致内存泄漏,而JVM有自己的内存管理机制,开发同学不用过多关注内存的申请和释放,集中精力放到业务实现上,内存的分配和回收都由JVM去管理(虽然JVM也可能会导致内存泄漏,更多的原因可能是代码问题或者内存分配及垃圾回收参数配置不合理,调优即可)。
在java程序中,对象占用的空间内存分配由JVM来分配,对象无任何引用不再使用时,由JVM选择合适的时机进行垃圾回收,自动释放所占用的空间。
虚拟机栈
虚拟机栈描述的方法执行的内存模型。在每个方法执行的同时会创建一个栈帧,用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法调用执行完成,都对应着一个栈帧在虚拟机中入栈到出栈的过程。
局部变量表:存放的是方法参数和方法内定义的变量。局部变量表在编译时就确定了局部变量表的大小, 一个局部变量可以保存一个类型为boolean、byte、char、short、int、float、long、double、reference和returnAddress类型的数据。 long和double占用2个局部变量空间,其余类型占用1个局部变量空间。
操作数栈:和局部变量表一样,操作数栈在编译时也确定了栈深度。操作数栈可以理解为java虚拟机栈中的一个用于计算临时数据的存储区(寄存器)。
动态连接: 一个方法调用另一个方法,在栈帧中只会存储另一个方法的符号引用,需要将其转换成内存地址。
方法出口:保存现场和恢复现场。
虚拟机栈的大小默认是1M。
本地方法栈
java调用c/c++的动态链接库,运行里面函数所需要的栈。JNI
Hot-Spot虚拟机直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈也会在栈深度溢出或者栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。
方法区
方法区只是一个java虚拟机的规范,在jdk8以前方法区的具体实现是***永久代***,jdk8方法区的具体实现***元空间***
主要存储类的元信息(IntanceKlass)
Java7及以前版本的Hotspot中方法区位于永久代中。同时,永久代和堆是相互隔离的,但它们使用的物理内存是连续的。 永久代的垃圾收集是和老年代捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。 但在Java7中永久代中存储的部分数据已经开始转移到Java Heap或Native Memory中了。比如,符号引用(Symbols)转移到了Native Memory;字符串常量池(interned strings)转移到了Java Heap;类的静态变量(class statics)转移到了Java Heap
JVM内存结构主要有三大块:堆(heap space)、方法区(method area/ PermGen/ MetaSpace)、本地区(native area)。
堆内存
堆内存(heap space)存放所有线程共享的对象和数组。在虚拟机启动时创建,Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”。GC回收的策略是按代回收。
对象在实例化后的整个运行周期内,都被存放在堆内存中。堆内存又被划分成不同的部分:是JVM中最大的一块由年轻代(Young Generation Space)和老年代(Old Generation Space)组成。而年轻代内存又被分成三部分,伊甸区(Eden)、From Survivor空间、To Survivor空间(幸存者区域(Survivor Sapce)包括From Survivor空间、To Survivor空间)。默认情况下年轻代按照8:1:1的比例来分配。