JVM概述
1、一些性能上的问题
- 我好好运行的线上系统突然间卡死了,系统无法访问,当然这个原因非常多;
- 想解决线上的JVM GC问题却无从下手;
- 新的项目上线了,对于各种JVM参数的设置一脸茫然,全部直接默认;
什么是Java虚拟机(JVM)?
JVM(Java Virtual Machine),是一种能够执行Java字节码的虚拟机。
JVM是Java平台的基石,Java应用服务器实质是JVM的一种扩展,而Java应用程序则运行在JVM之上。Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。
JVM是Java跨平台的核心机制,它主要由类加载器、运行时数据区、执行引擎、本地方法接口等几个部分组成。JVM的主要职责包括加载代码、校验代码、执行代码、输出执行结果等。当Java编译器完成了源代码文件(.java)的编译工作之后,就生成了能被Java虚拟机识别的字节码文件(.class)。JVM在执行这些字节码文件时,需要进行加载、链接、初始化,然后调用相应的方法。
2、Java语言及Java生态图
2.1、OracleJDK与OpenJDK什么关系?
OracleJDK可以视为OpenJDK的一个衍生版本。这是因为Oracle公司在2006年收购了Sun Microsystems,从而获得了Java的知识产权和相关技术。随后,Oracle基于OpenJDK进行开发,并在其基础上发布了OracleJDK。
OpenJDK是Java语言的一个开源实现,项目肇始于2006年SUN公司在Java One大会上对Java的开源决定和承诺,并于2009年4月正式对公众发布。它遵循GPL协议,是Java社区的核心项目,由全球各地的开发者共同参与开发和维护。
而OracleJDK在OpenJDK的基础上添加了一些商业功能和工具,例如Java Mission Control、Java Flight Recorder和商业支持等。此外,OracleJDK还包含了一些与Oracle相关的特性,比如Oracle Advanced Compression和Oracle Real Application Testing。这使得OracleJDK在功能和工具方面相较于OpenJDK更为丰富。
总的来说呢,OracleJDK和OpenJDK都是Java开发工具包的重要组成部分,它们之间的关系是OracleJDK在OpenJDK的基础上进行了商业化的扩展和优化。这种关系使得开发者可以根据项目需求选择适合的JDK版本。
2.2、JDK和JVM是什么关系?
如何理解Java是一个跨平台的语言?
“一次编译到处运行”,当java源代码成功编译成字节码之后,如果想在不同的平台上运行的话就不需要再次编译了,但是,就现在来讲这个并不能说是一个特点了,Python、PHP、Perl、Ruby等有强大的编译器。跨平台已经成为了入门语言的必选特性了。
如何理解JVM是跨语言平台?
Java虚拟机根本不关心运行在其内部的程序到底是使用什么编程语言编写的,它只关心“字节码文件”
虽然Java不是最强大的语言,但是JVM是最强大的虚拟机
Java不存在内存溢出?内存泄漏?
想多了,当然不是的。
- 内存溢出,主要发生在当Java程序试图使用比系统给它更多的内存时就会内存溢出。系统就给它了那些,它还想超出一部分。这可能是因为程序中的某一个部分不断地申请新的内存空间,而没有适当的释放不再需要的内存,当JVM的堆内存达到了最大的限制时,就会抛出OutOfMemoryError的错误,这就是内存溢出;
- Java中最常见的就是堆内存溢出,Java程序的对象都存储在堆内存中,当堆内存中的对象数超过了JVM所分配的最大堆内存容量时,就会发生堆内存溢出。
- 除了堆内存溢出有外,还有栈内存溢出,通常时由于方法调用的递归层次太深而导致栈内存耗尽。
- 内存泄漏,是另一种情况,当应用程序持有不再需要的对象仍然被持有,无法被垃圾回收器释放,导致内存占用持续增加,最终耗尽可用内存。
- 在Java中,最常见的内存泄漏是由于对象的引用未被释放而导致。比如,当一个对象持有了对另一个对象的引用,而这个引用在程序中不再需要时却未被释放,这就会导致内存泄漏。
- 内存泄漏可能是由于程序逻辑错误、不良的对象引用管理或者使用第三方库时未正确的释放资源所导致的。
那么怎么解决内存的溢出和泄漏呢?
- 对于内存的溢出,可以通过增加堆内存大小(这个就得去调JVM的参数了,你再使用默认的就不能满足系统需求了)或者优化程序设计来减少内存的使用。
- 对于内存的泄漏,需要通过代码审查和分析来找出没有被释放引用的地方,并保证在不再需要对象时及时释放对其的引用。使用Java内置的垃圾回收器也能帮助检测和处理内存泄漏问题。
各种JVM
-
Sun Classic VM -->解释型
-
Exact VM --> Solaris
-
SUN公司的 HotSpot VM
-
BEA 的 JRockit --> 不包含解释器,服务器端,JMC
-
IBM 的 J9
-
KVM和CDC/CLDC Hotspot
-
Azul VM
-
Liquid VM
-
Apache Harmony
-
Microsoft JVM
-
TaobaoJVM
-
Graal VM --> 2018年,“Run Programs Faster Anywhere”
-
Dalvik VM
-
其他JVM:
Java Card VM、Squawk VM、JavaInJava、Maxine VM、Jikes RVM、IKVM.NET、Jam VM、Cacao VM、Sable VM、Kaffe、Jelatine JVM、Nano VM、MRP、Moxie JVM
2.3、JVM的生命周期
Java虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的。
虚拟机的退出有以下几种情况:
- 某线程调用Runtime类或者System类的exit方法,或Runtime类的halt方法,并且Java安全管理器也允许这次exit或halt的操作;
- 程序正常的执行结束;
- 程序在执行过程中遇到了异常或错误而异常终止;
- 由于操作系统出现错误而导致Java虚拟机进程终止;
2.4、重点说一下HotSpot
- SUN的JDK版本从1.3.1开始运用HotSpot虚拟机, 2006年底开源,主要使用C++实现,JNI接口部分用C实现。
- HotSpot是较新的Java虚拟机,使用JIT(Just in Time)编译器,可以大大提高Java运行的性能。
- Java原先是把源代码编译为字节码在虚拟机执行,这样执行速度较慢。而HotSpot将常用的部分代码编译为本地(原生,native)代码,这样显着提高了性能。
- HotSpot JVM 参数可以分为规则参数(standard options)和非规则参数(non-standard options)。 规则参数相对稳定,在JDK未来的版本里不会有太大的改动。 非规则参数则有因升级JDK而改动的可能。
2.5、JVM架构图
这个架构可以分成三层看:
- 最上层:javac编译器将编译好的字节码class文件,通过java类装载器执行机制,把对象或class文件存放在jvm划分内存区域。
- 中间层:称为Runtime Data Area,主要是在Java代码运行时用于存放数据的,从左往右为方法区(永久代、元数据区)、堆(共享,GC回收对象区域)、栈、寄存器、本地方法栈(私有)。
- 最下层,解释器、JIT(just in time)编译器和GC(Garbage Collection,垃圾回收器);
JVM的几块知识