目录
什么是Java虚拟机(JVM)
Java虚拟机(Java Virtual Machine,JVM)是Java平台的关键组成部分,它是一种在不同操作系统上运行Java程序的虚拟计算机。
JVM的作用是执行Java字节码(Java bytecode),它是由Java编译器生成的中间代码,而不是直接执行源代码。
Java虚拟机的作用
字节码执行
JVM的主要作用是执行Java程序的字节码。在Java应用程序开发中,Java源代码首先被编译成字节码文件(.class文件),而不是本地机器码。这个字节码是一种与平台无关的中间表示,可以在任何支持Java的平台上运行。
JVM字节码的执行过程大概可以分为以下几个步骤:
- 装载:虚拟机启动后,通过类加载器将.class文件加载到内存中,并进行解析。
- 链接:将被引用的类、方法、变量等符号引用转化为直接引用,并将常量池中的符号引用替换为直接引用。
- 初始化:对类进行初始化。包括执行类构造器<clinit>()方法,静态变量赋值等。
- 解释执行:将解析后的字节码逐行解释执行,根据操作码执行相应的操作。
- 编译执行:如果某个方法被多次执行,JIT编译器会将其编译为本地代码,以提高执行效率。
- 垃圾回收:JVM自动进行垃圾回收,将不再使用的对象进行回收,释放内存空间。
总的来说,JVM字节码的执行过程包括“装载-链接-初始化-解释执行/编译执行-垃圾回收”等几个步骤,其中解释执行和编译执行是主要的执行方式。
跨平台兼容性
JVM跨平台兼容性的原因是因为Java程序编译后生成的是字节码(ByteCode)而不是特定平台上的机器码(Machine Code)。也就是说,Java程序并不是直接翻译成本地平台上的机器码,而是转换成JVM可以识别的字节码,最终由JVM解释执行或编译成本地平台上的机器码。也就是说JVM充当了一个中间层,负责将字节码翻译成特定操作系统的机器码。
这样做的好处是,由于Java程序并不会直接依赖于本地操作系统或硬件,所以只要有支持Java虚拟机的平台,就可以在该平台上运行Java程序,而不需要对程序进行修改。
这种跨平台机制使得Java程序可以在多个操作系统上进行编译和执行,从而使得Java成为一种性能良好、易于移植的语言。因此,JVM被认为是一种跨平台运行的虚拟机,Java也因此而被大量使用。
内存管理
JVM中的内存主要分为以下几个部分:
- 方法区(Method area):用于存储类的相关信息,如类的名称、方法、变量等信息。
- 堆(Heap):用于存储对象实例以及数组,是Java程序中最大的一块内存区域,也是垃圾回收的重点区域。
- 虚拟机栈(VM Stack):每个线程在运行时会创建一个虚拟机栈,用于存储局部变量以及方法执行的信息。
- 本地方法栈(Native Method Stack):用于执行本地方法,和虚拟机栈类似。
JVM的内存管理由两个部分实现:垃圾回收和内存分配。其中,垃圾回收是JVM的核心功能之一。
垃圾回收
JVM的垃圾回收机制主要是通过标记-清除和复制算法实现的。在JVM中,当一个对象不再被引用时,它就会被当作垃圾回收。JVM在运行时会不断扫描堆内存中的对象,标记哪些对象是活动对象,哪些对象是垃圾对象,然后清除垃圾对象,释放内存空间,以便被后续的对象使用。
内存分配
JVM的内存分配主要是通过分配器实现的。Java中的内存分配是动态分配的,也就是说,内存的分配和释放都是在运行时动态完成的。分配器会在堆中寻找一段足够的空间,然后将空间中的一部分分配给对象,同时标记已分配的空间,以便后续的内存分配使用。如果堆的空间不够了,就会触发垃圾回收,释放一些内存,然后再进行内存分配。
总的来说,它通过垃圾回收(Garbage Collection)来自动管理对象的生命周期,分配和释放内存,以避免内存泄漏和提高程序的性能,保证了Java程序的可靠性和稳定性。
性能优化
JVM 的性能优化需要从多个方面入手,通过内存管理、JIT 编译器、线程管理、JIT 栈上分配和类加载机制等,通过合理地设置,可以提高代码的执行效率和系统的整体性能。这里我们主要说明JIT 编译器、线程管理、JIT 栈上分配
即时编译器(Just-In-Time ,JIT )
在 Java 中,源代码经过编译器编译后会生成 Java 字节码,字节码是一种中间代码,在运行时需要通过解释器转换为本地机器码才能执行。这个过程会占用较多的时间,导致程序的执行速度较慢。为了解决这个问题,Java 引入了 JIT 技术。
JIT 是 Java 虚拟机的一种优化技术,它可以将热点代码(频繁执行的代码段)编译成本地机器码,以提高程序的执行性能。JIT编译器根据程序的运行情况进行优化,将字节码转化为更高效的本地机器指令。
线程管理
JVM 中的线程管理可以通过调整线程数和线程优先级来优化代码的执行效率。线程数的过多会导致系统资源的浪费,线程的优先级过高会导致其它线程无法获得 CPU 时间,从而降低系统的整体性能。
JIT 栈上分配
JIT 栈上分配(Stack Allocation)是指在 Java 虚拟机中,某些对象可以在栈上分配并随着栈帧的弹出而释放,而不是在堆上动态分配和回收。这种优化技术主要用于方法的临时对象,如循环中创建的对象等,通过减少堆内存的使用和垃圾回收的频率,提高代码的执行效率。
在 Java 中,对象的创建和销毁都是在堆内存中进行的。当对象不再使用时,JVM 会通过垃圾回收机制将其回收,并将内存释放出来。但是,在大量使用临时对象的场景中,由于堆内存管理的开销较大,频繁地创建和释放对象会导致系统性能下降。因此,JIT 栈上分配技术便应运而生。
当 JVM 检测到某些对象只在方法的生命周期内使用,并且不会逃逸到方法外部时,就可以使用 JIT 栈上分配技术将其分配到栈上。这样一来,对象的创建和销毁都可以随着栈帧的创建和销毁而自动完成,不需要通过垃圾回收机制进行管理。这种技术可以有效地减少堆内存的使用和垃圾回收的频率,从而提高代码的执行效率。
安全性
Java虚拟机(JVM)提供了多种安全性特性,这些特性旨在确保Java应用程序的安全性,并防止恶意代码的执行。以下是一些主要的安全性特性:
-
字节码验证: 在类加载的过程中,JVM会对字节码进行验证,以确保其合法性和安全性。这个验证过程包括对代码结构的检查、类型检查、访问权限检查等。它防止了一些常见的安全漏洞,如栈溢出、访问未经授权的内存等,这有助于防止恶意代码的执行。
-
类加载机制: JVM的类加载机制保证了类的安全性。类加载过程中执行的验证和安全检查确保加载的类不会损害JVM或底层系统的安全。
-
安全管理器(Security Manager): JVM提供了一个安全管理器,用于控制Java程序对系统资源的访问权限,比如文件、网络等。开发人员可以定义安全策略文件,规定哪些操作是被允许的,哪些是被拒绝的,以保护系统免受恶意代码的损害。
-
沙箱环境(Sandbox Environment): JVM提供了一个安全的沙箱环境,使Java程序能在受控制的环境中运行。这种环境限制了程序的访问权限,防止程序对系统的不良影响。
-
安全性类库: Java标准库提供了一些用于加密、数字签名、安全通信等的类和API,使开发者能够在程序中实现更高级的安全功能。
-
异常处理: JVM的异常处理机制可以捕获和处理各种异常,包括安全性方面的异常,确保程序在面临安全问题时能够进行适当的处理。
多线程支持
JVM支持多线程编程,提供了线程管理和同步机制,从而提高程序的性能和吞吐量,使多线程应用程序的开发变得更加容易。
线程的创建方式:http://t.csdnimg.cn/f0PMR
类加载
JVM的类加载是指将Java类文件加载到JVM内存中,并生成对应的Java类对象的过程。JVM的类加载器(ClassLoader)负责类加载,它将类文件读取到内存中,并将其转换为Java类对象。
JVM的类加载器有三种:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader)。其中,启动类加载器和扩展类加载器是JVM自带的类加载器,而应用程序类加载器是由JVM开发人员自己编写的。
JVM的类加载过程分为三个阶段:加载(Loading)、连接(Linking)和初始化(Initialization)。具体过程如下:
-
加载阶段:类加载器从文件系统或者网络中读入.class文件,并生成一个对应的Class对象。
-
连接阶段分为三个步骤:
- 验证(Verification):对类文件进行合法性验证,以保证类文件符合JVM规范和安全性要求。
- 准备(Preparation):为类的静态变量分配内存,并设置默认初始值。
- 解析(Resolution):将类的符号引用转换为直接引用。
-
初始化阶段:对类进行初始化,包括执行静态变量赋值和静态代码块等。
JVM在程序运行时动态加载类文件,这意味着可以在运行时引入新的类和库,从而实现模块化和可扩展的应用程序设计。
异常处理
在JVM中,异常处理是通过抛出(throw)和捕获(catch)异常来实现的。Java语言中的所有异常都是Throwable类或其子类的实例,分为两种类型:Checked Exception和Unchecked Exception。Checked Exception必须在代码中进行处理,而Unchecked Exception通常是由程序中的错误引起的,并且不需要进行处理。
JVM通过栈轨迹(stack trace)来追踪异常的发生和处理过程。当异常发生时,JVM将追踪栈的状态保存到一个异常对象中,然后通过抛出异常方式将这个异常对象传递到调用栈上,直到找到一个能够处理该异常的catch块。
JVM中的异常处理机制包括以下几个步骤:
- 当代码中出现异常时,JVM将创建一个异常对象,并将其抛出。
- 异常对象将被传递到调用栈上,直到找到一个能够处理该异常的catch块。
- 在catch块中,程序可以对异常进行处理,例如打印日志、重新抛出异常或者返回一个默认值。
- 如果没有找到能够处理异常的catch块,则程序将终止,并打印异常的堆栈轨迹。
JVM的异常机制可以使程序更加健壮和稳定,它能够帮助程序员快速定位和修复代码中的问题。同时,在编写Java程序时,我们也应该注意正确地处理异常,以便提高程序的可靠性和健壮性。
总之,Java虚拟机充当了Java程序和底层操作系统之间的重要中介,使Java的跨平台特性成为可能。它提供了内存管理、性能优化、安全性、多线程支持等关键功能,使Java成为一种流行的编程语言,广泛应用于各种应用领域,包括企业级应用、移动应用、嵌入式系统和大数据处理等。