Java JVM原理与性能调优:从基础到高级应用

一、JVM基础架构与内存模型

1.1 JVM整体架构概览

Java虚拟机(JVM)是Java程序运行的基石,它由以下几个核心子系统组成:

子系统 功能描述 类比解释
类加载子系统 负责加载.class文件到内存 像图书馆管理员,负责把书(类)从书架(磁盘)拿到阅读区(内存)
运行时数据区 程序运行时的内存区域 相当于图书馆的不同功能区(阅览区、储物柜等)
执行引擎 解释/编译字节码并执行 像翻译官,把Java字节码翻译成机器码
本地方法接口 调用本地方法库 像外语翻译,调用非Java编写的功能
垃圾回收系统 自动内存管理 像清洁工,回收不再使用的内存空间

1.2 运行时数据区详解

JVM内存主要分为以下几个区域:

public class MemoryStructure {
   
   
    static int staticVar = 1;          // 方法区(类静态变量)
    int instanceVar = 2;               // 堆内存(实例变量)
    
    public void method() {
   
   
        int localVar = 3;             // 栈帧中的局部变量表
        Object obj = new Object();     // obj引用在栈,对象实例在堆
        MemoryStructure mem = new MemoryStructure();
    }
}
1.2.1 程序计数器(PC Register)
  • 线程私有,记录当前线程执行的字节码行号
  • 唯一不会发生OOM的区域
1.2.2 Java虚拟机栈(VM Stack)

栈用于存储局部变量和方法调用的信息。可以把栈想象成一个 “千层饼”,每一层代表一个方法的调用,当方法调用结束后,该层就会被移除。

  • 线程私有,存储栈帧(Stack Frame)
  • 栈帧包含:局部变量表、操作数栈、动态链接、方法返回地址
public class StackExample {
   
   
    public static void main(String[] args) {
   
   
        int a = 1;          // 局部变量表slot 0
        int b = 2;          // 局部变量表slot 1
        int c = add(a, b);  // 创建新的栈帧
    }
    
    public static int add(int x, int y) {
   
   
        int sum = x + y;    // 新栈帧的局部变量表
        return sum;
    }
}

在上述代码中,main 方法和 add 方法的局部变量(如 abxy)以及方法调用信息都存放在栈中。

1.2.3 本地方法栈(Native Method Stack)
  • 为本地方法服务,类似虚拟机栈
  • HotSpot中将虚拟机栈和本地方法栈合二为一
1.2.4 堆内存(Heap)

堆是 JVM 中最大的一块内存区域,用于存储对象实例。可以把堆想象成一个大仓库,所有的对象都存放在这里。

  • 线程共享,存放对象实例
  • GC主要工作区域
  • 可分为新生代(Eden, Survivor)、老年代
// 创建一个对象,存放在堆中
public class HeapExample {
   
   
    public static void main(String[] args) {
   
   
        // 创建一个Person对象,存放在堆中
        Person person = new Person(); 
    }
}

class Person {
   
   
    private String name;
    private int age;

    // 构造方法
    public Person() {
   
   
        this.name = "John";
        this.age = 30;
    }
}

在上述代码中,new Person() 创建的 Person 对象实例就存放在堆中。

1.2.5 方法区(Method Area)

方法区用于存储类的信息、常量、静态变量等。可以把方法区想象成一个 “知识库”,存储着类的各种知识和规则。

  • 存储类信息、常量、静态变量等
  • JDK8后由元空间(Metaspace)实现,使用本地内存
public class MethodAreaExample {
   
   
    // 静态变量,存放在方法区
    public static final String MESSAGE = "Hello, World!"; 

    public static void main(String[] args) {
   
   
        System.out.println(MESSAGE);
    }
}

在上述代码中,MESSAGE 静态常量存放在方法区。

1.3 内存区域对比

内存区域 线程共享 是否GC 可能异常 配置参数
程序计数器 私有
虚拟机栈 私有 StackOverflowError/OutOfMemoryError -Xss
本地方法栈 私有 StackOverflowError/OutOfMemoryError 同虚拟机栈
堆内存 共享 OutOfMemoryError -Xms, -Xmx, -Xmn
方法区 共享 OutOfMemoryError -XX:MetaspaceSize

二、类加载机制与字节码执行

2.1 类加载过程

类加载的过程包括加载、连接(验证、准备、解析)和初始化。可以把类加载的过程想象成一场演出的筹备过程,加载就像是邀请演员(类),连接就像是安排演员的服装、道具等,初始化就像是演员正式登台表演。

类加载分为以下五个阶段:

阶段 功能描述 通俗解读
加载 通过类的全限定名获取类的二进制字节流,并将其转换为方法区中的运行时数据结构,在堆中创建对应的 Class 对象 邀请演员到演出场地
验证 确保字节码文件的正确性和安全性 检查演员的身份和资质
准备 为类的静态变量分配内存并设置初始值 为演员准备服装和道具
解析 将符号引用转换为直接引用 确定演员在舞台上的具体位置
初始化 执行类的静态代码块和静态变量的赋值操作 演员正式登台表演
public class ClassLoadExample {
   
   
    static {
   
   
        System.out.println("静态代码块执行");  // 初始化阶段执行
    }
    
    public static int value = 123;  // 准备阶段赋0,初始化阶段赋123
    
    public 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clf丶忆笙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值