“Yeah It’s on. ”
JVM
JVM,JRE,JDK的关系
jvm就是java程序的运行环境,负责将java字节码.class文件解释或者编译成机器码,并在不同平台上执行
jre包含jvm和java核心库的运行环境,提供了java运行程序所需的所有内容
jdk适用于java开发的完整开发环境,包含jre,编译器javac,调试工具 等
JVM(Java Virtual Machine)、JRE(Java Runtime Environment)和JDK(Java Development Kit)是Java开发和运行环境中的三个重要概念。它们之间的关系和区别如下:
1. JVM(Java虚拟机)
- 作用:JVM是Java程序的运行环境。它的主要职责是将Java字节码(.class文件)解释或编译成机器码,并在不同的平台上执行。JVM负责Java程序的跨平台特性(”一次编写,到处运行”)。
- 独立性:JVM是与操作系统无关的,Java程序通过JVM可以在任何安装了JVM的设备上运行。
2. JRE(Java运行环境)
- 组成:JRE是包含JVM和Java核心库(如Java API类库)的运行环境。它提供了Java应用程序运行所需的所有内容。
- 用途:JRE用于执行已经编译好的Java程序(.class文件)。它不包含编译Java源代码(.java文件)所需的工具。
3. JDK(Java开发工具包)
- 组成:JDK是用于Java开发的完整开发环境。它包含JRE(即JVM和Java核心库)、编译器(javac)、调试工具、以及其他开发工具。
- 用途:JDK是Java开发者编写、编译、调试和运行Java程序所需的工具集合。开发人员用JDK将Java源代码编译为字节码,然后用JRE来执行这些字节码。
三者之间的关系
- JDK包含JRE,JRE包含JVM:JDK是开发工具包,其中包含了运行Java程序所需的JRE,而JRE中又包含了真正执行字节码的JVM。
- 开发与运行:JDK主要用于开发阶段,提供了编译、调试等工具,而JRE主要用于运行阶段,提供了运行Java应用程序的环境。
简而言之,JVM是Java程序的运行时核心,JRE是运行环境,而JDK是开发工具包。JDK包含了JRE,而JRE包含了JVM。
追问: java是编译型语言还是解释型语言?
JIT(Just-In-Time Compilation)
- 作用:JIT是JVM中的一种即时编译技术。在程序运行时,JIT会将热点字节码(多次执行的代码)编译为机器码,以提高执行效率。
- 特点:JIT编译是动态的,只有在程序运行过程中需要时才会发生。这种编译方式结合了解释执行和编译执行的优势,提供了更好的性能。
AOT(Ahead-Of-Time Compilation)
- 作用:AOT是指在程序运行之前将字节码提前编译为机器码。这种编译方式可以减少程序的启动时间,因为在运行时不需要再进行编译。
- 区别于JIT:与JIT不同,AOT编译是在程序部署或安装时完成的,不依赖于程序的运行时环境。AOT通常用于需要更快启动时间或在资源受限环境中运行的应用程序。
Java 既是编译型语言,也是解释型语言。这是因为 Java 的执行过程包含了两者的特点:
1. 编译型语言的部分
- 编译阶段:Java 源代码(.java 文件)首先通过 Java 编译器(javac)编译成字节码(.class 文件)。这个编译过程将人类可读的源代码转换为平台无关的字节码。
2. 解释型语言的部分
- 解释执行阶段:生成的字节码不是直接在物理机上运行,而是由 Java 虚拟机(JVM)解释执行。JVM 会将字节码逐行解释成机器码,并在目标机器上执行。
3. JIT 编译的作用
- 即时编译(JIT):为了提高性能,JVM 还引入了即时编译(Just-In-Time Compilation, JIT)。JIT 编译器在运行时将热点代码(多次执行的代码)从字节码编译为机器码,从而减少解释执行的开销,使得 Java 程序在运行时能够达到接近原生编译语言的性能。
总结
Java 的执行过程结合了编译和解释两种方式:先编译再解释,并且在运行时使用 JIT 编译器将部分字节码编译成机器码。因此,Java 既具有编译型语言的特性,也具有解释型语言的特性。
JVM内存区域
1. 方法区(Method Area)
- 概述:方法区是所有线程共享的一块内存区域,用于存储类信息、常量池、静态变量、即时编译器(JIT)编译后的代码等。方法区有时也被称为永久代(在Java 8之前),而在Java 8及之后被称为元空间(Metaspace)。
- 用途:主要存储类的结构信息(如字段、方法的数据)、静态变量、常量、以及方法的字节码。
2. 堆区(Heap)
- 概述:堆区也是所有线程共享的内存区域,是Java应用程序中最大的一块内存区域,用于存储所有的对象实例和数组。
- 用途:几乎所有对象实例都在堆区中分配。堆区在Java应用中非常重要,GC(垃圾回收器)主要在此区域中进行对象的回收。
3. 栈区(Stack)
- 概述:栈区是线程私有的内存区域,每个线程都有一个独立的栈。栈区中保存着方法的局部变量表、操作数栈、动态链接、方法出口等信息。
- 用途:每当一个方法被调用时,JVM都会在栈中为该方法分配一块栈帧(Stack Frame),用于存储局部变量和中间计算的结果。方法调用结束后,栈帧就会被弹出并销毁。
4. 程序计数器(Program Counter Register)
- 概述:程序计数器是每个线程私有的一块较小的内存区域,用于记录当前线程所执行的字节码的行号指示器。
- 用途:在多线程环境下,程序计数器帮助线程恢复到正确的执行位置,从而实现线程间的切换。
5. 本地方法栈(Native Method Stack)
- 概述:本地方法栈也是线程私有的内存区域,与Java栈类似,但它为本地方法(Native Method)服务。本地方法是用其他语言(如C或C++)编写的方法,通过JNI(Java Native Interface)调用。
- 用途:当Java程序调用本地方法时,本地方法栈会记录这些方法的调用状态和执行过程。
JVM运行时内存
垃圾回收的算法
1. 标记-清除算法(Mark-and-Sweep)
- 原理:分为两个阶段:标记阶段和清除阶段。首先,从根对象开始标记所有可达的对象;然后,遍历堆中所有对象,回收那些没有被标记的对象。
- 优点:简单易实现,不会出现碎片问题。
- 缺点:可能导致内存碎片问题(特别是在堆中有大量不连续的空闲区域),回收过程中可能会造成停顿时间较长。
2. 标记-整理算法(Mark-and-Compact)
- 原理:在标记阶段和标记-清除算法相同,但是在清除阶段,它会整理堆中的对象,将所有存活对象移动到堆的一端,然后释放另一端的内存。
- 优点:避免了内存碎片问题,提高了内存的利用率。
- 缺点:对象移动可能会导致额外的开销,尤其是在对象比较大时。
3. 复制算法(Copying)
- 原理:将堆分成两部分。每次回收时,将存活对象从当前区域复制到另一块区域,然后清理当前区域。由于每次只使用一半的堆,因此避免了碎片问题。
- 优点:内存碎片问题较少,算法实现相对简单。
- 缺点:内存开销较大,因为需要两倍于实际堆大小的内存空间。
4. 分代收集算法(Generational Collection)
- 原理:将堆分为年轻代和老年代。年轻代中包含 Eden 区和两个 Survivor 区。年轻代中的对象通常较短寿命,而老年代则用于存放长寿命的对象。年轻代采用复制算法,而老年代通常使用标记-整理算法。
- 优点:针对不同生命周期的对象使用不同的回收策略,提高了效率,减少了GC停顿时间。
- 缺点:实现复杂度较高,需要在年轻代和老年代之间进行优化和调度。
5. 增量式回收(Incremental Collection)
- 原理:将垃圾回收的过程分成多个小的步骤,而不是一次性完成所有的回收工作。这样可以减少GC的停顿时间。
- 优点:适合需要低停顿时间的应用,尤其是在响应时间要求高的环境中。
- 缺点:可能导致回收的效率降低,因为每次只回收一小部分。
6. 并发回收(Concurrent Collection)
- 原理:与增量式回收类似,但并发回收是在应用程序运行的同时进行垃圾回收,尽量减少对应用程序执行的影响。
- 优点:降低了GC的停顿时间,提高了应用程序的响应性。
- 缺点:实现复杂,可能会带来更多的资源消耗和竞争。
7. 增量式并发回收(Incremental Concurrent Collection)
- 原理:结合了增量式和并发回收的优点,在多线程环境中并发地进行小步骤的回收。
- 优点:进一步减少了GC的停顿时间,适合对延迟敏感的应用。
- 缺点:实现复杂,可能会带来更多的资源消耗。
总结
- 标记-清除算法:简单,但可能导致内存碎片。
- 标记-整理算法:解决内存碎片问题,但可能带来对象移动的开销。
- 复制算法:避免碎片问题,但需要额外的内存空间。
- 分代收集算法:高效的分代策略,适用于大多数应用。
- 增量式回收:减少GC停顿时间,适合高响应性应用。
- 并发回收:在应用程序运行的同时进行回收,降低停顿时间。
- 增量式并发回收:结合了增量和并发的优点,进一步减少了GC停顿时间。
gc垃圾回收器有哪些
1. 串行垃圾回收器(Serial GC)
- 特性:适用于单线程环境,所有的垃圾回收操作都是在单个线程中完成的。它适合内存小、处理器资源有限的应用程序。
- 优点:实现简单,较低的内存开销,适用于客户端应用。
- 缺点:在大规模应用中可能导致长时间的停顿,因为回收过程中应用会被暂停。
- 使用:通过
-XX:+UseSerialGC
启用。
2. 并行垃圾回收器(Parallel GC,也称为吞吐量优先GC)
- 特性:利用多个线程进行垃圾回收,提高了回收效率,减少了停顿时间。它适合于多核处理器的服务器环境,追求较高的吞吐量。
- 优点:适用于多线程和大内存环境,能够利用多核处理器的优势。
- 缺点:可能在回收过程中导致较长的停顿。
- 使用:通过
-XX:+UseParallelGC
启用。
3. 并行压缩垃圾回收器(Parallel Old GC,也称为并行老年代GC)
- 特性:是 Parallel GC 的扩展,用于回收老年代的垃圾。它同样利用多个线程,提高了老年代的回收效率。
- 优点:可以提高老年代垃圾回收的效率,适用于高吞吐量应用。
- 缺点:在回收老年代时可能会有较长的停顿时间。
- 使用:通过
-XX:+UseParallelOldGC
启用。
4. 并发标记清除垃圾回收器(Concurrent Mark-Sweep GC,CMS)
- 特性:旨在减少停顿时间,采用并发的方式进行垃圾回收。它分为多个阶段:初始标记、并发标记、重新标记和最终清理。
- 优点:适用于需要较低停顿时间的应用,能够在应用程序运行时进行大部分的垃圾回收工作。
- 缺点:在并发回收阶段可能会出现内存碎片,并且在最终清理阶段可能仍会有短暂的停顿。
- 使用:通过
-XX:+UseConcMarkSweepGC
启用。
5. G1垃圾回收器(Garbage-First GC)
- 特性:旨在提高垃圾回收的预测性,减少停顿时间。G1 GC 将堆划分为多个区域(Region),并根据区域的垃圾回收情况进行选择性回收。
- 优点:可以提供可预测的停顿时间,适合大堆内存和需要低延迟的应用。
- 缺点:相对于其他垃圾回收器,G1 的实现和调优较为复杂。
- 使用:通过
-XX:+UseG1GC
启用。
6. ZGC(Z Garbage Collector)
- 特性:是一个低延迟的垃圾回收器,旨在减少 GC 停顿时间到毫秒级别。ZGC 使用了多种新技术,如并发标记、并发重定位和压缩技术。
- 优点:提供了极低的 GC 停顿时间,非常适合高性能和低延迟的应用。
- 缺点:对硬件要求较高,内存使用开销较大。
- 使用:通过
-XX:+UseZGC
启用。
7. Shenandoah GC
- 特性:也是一个低延迟的垃圾回收器,旨在减少停顿时间,并支持大堆内存的高效回收。Shenandoah GC 通过并发方式进行大部分的垃圾回收工作。
- 优点:提供了短暂停顿时间,适合需要高响应性的应用。
- 缺点:实现和调优复杂,内存开销较大。
- 使用:通过
-XX:+UseShenandoahGC
启用。
总结
- 串行GC:简单,适用于单线程和小内存环境。
- 并行GC:适用于多核环境,优化吞吐量。
- 并行老年代GC:扩展了并行GC,优化老年代回收。
- CMS:减少停顿时间,适用于低延迟应用。
- G1:提供可预测的停顿时间,适用于大堆内存应用。
- ZGC:极低的停顿时间,适合高性能应用。
- ShenandoahGC:低延迟,适合对响应时间要求高的应用。
不同的垃圾回收器有不同的优缺点,选择合适的垃圾回收器可以帮助优化应用程序的性能和响应时间。
JVM类加载
通过类加载器实现