开始改变第一天 JVM的原理到调优(2)

2025-12-12 0 488

JVM核心技术详解:从类加载到垃圾回收的完整流程

一、从源码到字节码:深入理解Java程序执行

1.1 源码与字节码对应关系

public class Person {
    private String name = \"Jack\";
    private int age;
    private final double salary = 100;
    private static String address;
    private final static String hobby = \"Programming\";
    
    public void say() {
        System.out.println(\"person say...\");
    }
    
    public static int calc(int op1, int op2) {
        op1 = 3;
        int result = op1 + op2;
        Object obj = new Object();  // 新增对象创建示例
        return result;
    }
    
    public static void order() {}
    
    public static void main(String[] args) {
        calc(1, 2);
        order();
    }
}

1.2 字节码指令分析

通过javap -c Person查看字节码:

public static int calc(int, int);
Code:
   0: iconst_3           // 将常量3压入操作数栈
   1: istore_0           // 将栈顶值存入局部变量op1
   2: iload_0            // 加载局部变量op1到栈
   3: iload_1            // 加载局部变量op2到栈  
   4: iadd               // 执行加法运算
   5: istore_2           // 结果存入局部变量result
   6: new           #12  // 创建Object对象 -> 堆内存
   9: dup                // 复制栈顶引用
   10: invokespecial #13 // 调用构造方法 -> 方法区
   13: astore_3          // 存储引用到局部变量obj
   14: iload_2           // 加载result到栈
   15: ireturn           // 返回结果

public static void main(java.lang.String[]);
Code:
   0: iconst_1           // 常量1入栈
   1: iconst_2           // 常量2入栈
   2: invokestatic  #10  // 调用calc方法 -> 方法区
   5: pop                // 弹出返回值
   6: invokestatic  #11  // 调用order方法
   9: return

二、运行时数据区深度解析

2.1 方法执行时的内存状态

main线程执行calc方法时的栈帧结构:

Java虚拟机栈 (Java Virtual Machine Stacks)
├── 栈帧 calc
│   ├── 局部变量表 (Local Variables)
│   │   ├── op1 = 3
│   │   ├── op2 = 2  
│   │   ├── result = 5
│   │   └── obj → [堆内存地址]
│   ├── 操作数栈 (Operand Stacks)
│   │   ├── 10 (临时值示例)
│   │   └── 3
│   ├── 动态链接 (Dynamic Linking) → 指向方法区的方法信息
│   └── 方法返回地址 (Invocation Completion)
└── 栈帧 main
    └── 局部变量表: args

2.2 Java对象内存布局

对象在堆内存中的结构:

对象头 (Header) [12-16字节]
├── Mark Word [8字节]
│   ├── 哈希码 (HashCode)
│   ├── GC分代年龄 (4bit)
│   ├── 锁状态标志 (2bit)
│   └── 线程持有的锁
├── 类型指针 (Class Pointer) [8字节,压缩后4字节]
└── [数组长度] [4字节,仅数组对象有]

实例数据 (Instance Data)
├── boolean/byte: 1字节
├── short/char: 2字节  
├── int/float: 4字节
├── long/double: 8字节
└── reference: 4-8字节

对齐填充 (Padding)
└── 保证对象大小为8字节的倍数

示例:Person对象内存计算

private String name;      // 引用: 4字节
private int age;          // int: 4字节  
private final double salary; // double: 8字节
// 对象头: 8(Mark Word) + 4(类指针) = 12字节
// 实例数据: 4 + 4 + 8 = 16字节
// 总大小: 12 + 16 = 28字节 → 对齐到32字节

三、堆内存分区与垃圾回收机制

3.1 堆内存分区设计

堆内存结构:

堆 (Heap)
├── 新生代 (Young Generation) [占堆1/3]
│   ├── Eden区 [80%]
│   └── Survivor区 [20%]
│       ├── Survivor0 (S0) [10%]
│       └── Survivor1 (S1) [10%]
└── 老年代 (Old Generation) [占堆2/3]

分配比例:Eden : S0 : S1 = 8 : 1 : 1

3.2 对象分配与晋升机制

对象分配流程:

  1. 新对象创建 → 优先在Eden区分配
  2. Eden空间不足 → 触发Minor GC
  3. GC后存活对象 → 移动到Survivor区
  4. 对象年龄增长 → 每次Minor GC后年龄+1
  5. 年龄阈值(默认15) → 晋升到老年代

GC类型说明:

  • Minor GC:年轻代(Eden + Survivor)垃圾回收,频繁但快速
  • Major GC:老年代垃圾回收
  • Full GC:整个堆(年轻代+老年代)垃圾回收,STW(Stop The World)时间长

3.3 垃圾回收算法核心思想

为什么需要分代收集?

  • 统计规律:大部分对象\”朝生夕死\”(生命周期短)
  • 优化策略:对新生代频繁GC,对老年代减少GC频率

空间分配担保机制:

  • 当Survivor区空间不足时,老年代提供\”分配担保\”
  • 确保对象在年轻代GC时能够有地方存放

避免内存碎片:

  • Survivor区采用复制算法,保证S0/S1总有一个为空
  • 解决内存碎片问题,提高内存利用率

四、完整的JVM架构体系

JVM完整组件架构:

类文件 (Class File)
↓
类加载器子系统 (ClassLoader Subsystem)
├── 加载 (Loading)
├── 链接 (Linking)
└── 初始化 (Initialization)
↓
运行时数据区 (Runtime Data Areas)
├── 方法区 (Method Area) ← 类信息、常量、静态变量
├── 堆 (Heap) ← 对象实例
├── 虚拟机栈 (JVM Stacks) ← 栈帧
├── 本地方法栈 (Native Method Stacks)
└── 程序计数器 (PC Register)
↓
执行引擎 (Execution Engine)
├── 解释器 (Interpreter)
├── JIT编译器 (Just-In-Time Compiler)
└── 垃圾收集器 (Garbage Collector)
↓
本地方法接口 (Native Method Interface)

五、性能优化关键点

5.1 GC优化策略

  1. 减少Full GC频率

    • 合理设置堆大小:-Xms(初始堆)、-Xmx(最大堆)
    • 调整新生代比例:-XX:NewRatio(新生代/老年代比例)
    • 优化Survivor区:-XX:SurvivorRatio(Eden/Survivor比例)
  2. 监控GC状态

    # 启用GC日志
    -XX:+PrintGCDetails -Xloggc:gc.log
    # 实时监控
    jstat -gc  1000
    

5.2 内存参数调优

# 堆内存设置
-Xms2g -Xmx2g           # 初始和最大堆内存
-XX:NewRatio=2          # 新生代:老年代=1:2  
-XX:SurvivorRatio=8     # Eden:S0:S1=8:1:1

# GC算法选择
-XX:+UseG1GC            # G1垃圾收集器
-XX:MaxGCPauseMillis=200 # 最大GC停顿时间

六、总结

通过深入分析JVM的完整执行流程,我们可以得出以下关键理解:

  1. 类加载机制确保代码的正确加载和初始化
  2. 运行时数据区各司其职,协同完成程序执行
  3. 堆内存分代设计基于对象生命周期统计规律
  4. 垃圾回收策略平衡性能与内存利用率
  5. 监控与调优是保证应用性能的关键

理解JVM内部机制不仅有助于写出高性能代码,更能帮助我们在遇到性能问题时快速定位和解决。下一节我们将深入探讨各种垃圾回收器的实现原理和适用场景。
怎么设计垃圾回收(下一个文章详细介绍)
垃圾回收机制
(1)确定什么样的对象是垃圾?
引用计数【会有问题,循环引用的问题】
可达性分析【GC Root,由它出发,某个对象Person对象是否可达】

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 开始改变第一天 JVM的原理到调优(2) https://www.zuozi.net/35698.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务