JVM介绍

发布于:2025-09-15 ⋅ 阅读:(22) ⋅ 点赞:(0)

JVM(Java虚拟机)是Java跨平台特性的核心。它是一个虚构的计算机,通过在实际计算机上模拟计算机功能来实现的。

JVM的作用

  • 跨平台运行:Java源码编译为字节码后(.class文件),jvm负责将字节码解释或编译为本地机器码执行。实现“一次编写,多处运行“。
  • 内存管理:自动进行内存分配和垃圾回收,减少手动内存管理的错误。
  • 安全控制:通过字节码验证器等机制确保代码安全执行。

核心组件

  • 类加载器(ClassLoader):负责将.class文件加载到JVM中,分为BootStrap ClassLoader(加载核心类库)、Extension ClassLoader(加载扩展类库)、ApplicationClassLoader(加载应用程序)。
  • 运行时数据区:
    • 方法区:存储类信息,常量、静态变量(JDK8之后移至元空间Metaspace,使用本地内存)
    • 堆:存储对象实例,是垃圾回收的主要区域,线程共享。
    • 虚拟机栈:每个线程私有,存储方法调用的栈帧(包含局部变量表,操作数栈等)。
    • 本地方法栈:类似虚拟机栈,但为Native方法服务。
    • 程序计数器:记录当前线程执行的字节码指令地址,线程私有。
  • 执行引擎:负责执行字节码,包括解释器(逐行解释执行)和即时编译(JIT,将热点代码编译为机器码缓存)。
  • 垃圾回收器(GC):自动回收堆中不再使用的对象内存。

垃圾回收GC

  • 回收区域:主要针对堆内存(新生代和老年代)
  • 判断对象存活:常用可达性分析算法,通过GC Roots(如虚拟机栈引用的对象,静态变量引用的对象等)判断对象是否可达。
  • 垃圾收集算法:
    • 标记-清除:标记需要回收的对象,然后清除,会产生内存碎片。
    • 标记-复制:将内存分为两块,只使用一块,回收时将存活对象复制到另一块,适用于新生代。
    • 标记-整理:标记后将存活对象向一端移动,然后清除边界外内存,使用老年代。
  • 常见收集器:Serial GC、ParelleGC、CMS(Concurrent Mark Sweep)、G1、ZGC、Shenandoah等,各有不同性能特点。

垃圾回收的核心目标

  • 识别垃圾:判断哪些对象已经不再被程序使用(”死亡对象")。
  • 回收内存:释放死亡对象占用的内存,供新对象使用。
  • 高效执行:在不显著影响程序运行的前提下完成回收。(低延迟、高吞吐量)

判断对象“死亡”

JVM通过可达性分析算法判断对象是否存活。

  1. GC Roots:作为根节点的对象(如虚拟机栈中引用的对象、静态变量引用的对象、常量池引用的对象、本地方法栈中引用的对象等)。
  2. 可达性链条:从GC Roots出发,所有能被直接或间接引用的对象都是“存活”的,反之,无法到达的对象被标记为“死亡”。

垃圾回收算法

JVM根据**不同内存区域的特点(如对象存活时间)**采用不同的回收算法:

  1. 标记-清除算法(Mark-Sweep)
    • 步骤:先标记所有死亡的对象,在统一清除这些对象。
    • 优点:简单直接。
    • 缺点:会产生大量内存碎片,可能导致后续 大对象 无法分配内存。
  2. 标记-复制算法(Mark-Copy)
    • 将内存分为两块 (如Eden区 和 Survivor区),只是用其中一块,回收时将存活对象复制到另一块,然后清空原内存块。
    • 优点:无内存碎片,实现简单。
    • 缺点:内存利用率低(仅利用一半),适合对象存活率低的场景(如新生代)。
  3. 标记-整理算法(Mark-Compact)
    • 步骤:标记死亡对象后,将所有存活对象向内存 一端移动,然后清除边界外的内存。
    • 优点:无内存碎片,内存利用率高。
    • 缺点:移动对象的成本高,适合对象存活率高的场景(如老年代)。

堆内存的分代 回收策略

JVM将堆内存划分为不同区域,针对各自区域特点采用不同的回收策略(分代思想)

  1. 新生代(Young Generation)
    • 存储新创建的对象,对象存活率低(大部分很快死亡)
    • 分为Eden区和Survivor区 (From区和To区,大小通常1:1)
    • 回收流程:
      • 新对象优先分配大Eden区。
      • Eden区满时触发Mintor GC(新生代回收),存活对象复制到From Survivor区。
      • 再次回收时,Eden区和From区的存活对象复制到To区,年龄+1。
      • 当对象年龄到达15岁时,晋升老年代
  2. 老年代(Old Generation)
    • 存储存活时间长的对象(如缓存对象),存活率高。
    • 次啊用标记-整理算法,回收频率低。
    • 当老年代内存不足时,触发Major GC/Full GC(全堆回收,包括新生代和老年代),耗时较长
  3. 元空间
    • 存储类信息、常量池等,替代JDK7的永久代(Perm Gen)。
    • 使用本地内存,默认无上限(可通过参数设置)。一般不参与垃圾回收

类加载机制

  • 加载过程:加载(获取字节流) - 验证(确保字节码安全)- 准备(为静态变量分配内存并设置默认值) - 解释(将符号引用转为直接引用)-初始化(执行类构造器《clinit()方法)
  • 双亲委派模型:加载类时,先委托父类加载器加载,父类无法加载时才由子类加载器尝试,避免类的重复加载和核心类篡改

JVM调优

  • 调优参数:通过JVM参数调整内存大小(如:-Xms、-Xmx),设置初始化堆大小,选择合适的垃圾收集器(如:XX:Use G1GC),设置新生代和老年代比例等。
  • 性能监控工具:jsp(查看进程)、jstat(统计信息)、jmap(内存映射)、jstack(线程堆栈)、Visual VM等。

hotSpot VM 介绍

核心工作原理:字节码执行和内存管理。通过 热点代码优化 和 分代垃圾回收 实现。

类加载:将字节码转为可执行的类对象。

HotSpot首先通过**类加载器(Class Loader)**完成类的加载,确保籽伽玛合规并转为 JVM可识别的结构。遵循 双亲委派模型

  1. 加载:从磁盘/网络中 加载 .class文件(字节码),将其转为JVM内部的“类元数据”(存储在方法区/元空间)。
  2. 验证:校验字节码合法性(格式、语法和安全权限),防止恶意代码执行。
  3. 准备:为类的静态变量分配内存并设置默认值,
  4. 解析:将类中引用(如类名、方法名)转为直接引用(内存地址)。
  5. 初始化:执行静态代码和静态变量的显式赋值,此时类可使用。

字节码执行:混合”解释执行“和“即时编译”

HotSpot不直接执行字节码,而是通过 ”解释器“+JIT及时编译” 混合模式,平衡 启动速度和运行性能。

  • 第一步:解释执行(启动阶段)
  • 第二步:热点代码探测和JIT编译(运行阶段)

内存管理:分代模型 + 多垃圾回收适配

HotSpot基于 “对象生命周期差异”设计分代内存模型,并适配不同的垃圾回收模型。核心逻辑:

  • 内存分代划分(堆内存):
    • 新生代:
    • 老年代:
    • 元空间:
  • 垃圾回收触发:
    • 新生代满,触发Minor GC。
    • 老年代/元空间 满触发MajorGC/Full GC (回收老年代和新生代),会导致程序停顿(STW),需要通过G1/ZGC等回收器减少停顿时间。

线程与并发:轻量级同步机制

HotSpot通过对象头(Mark Word)监视器(Monitor)实现Java并发同步,核心是锁优化以减少阻塞开销。

  • 锁状态升级: