JVM内存模型详解

一、JVM内存结构总览

┌─────────────────────────────────────────────────────────────────┐
│                      JVM 运行时数据区                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ================== 【线程共享区域】===================         │
│  │                                                            │ │
│  │  ┌───────────────────────────────────────────────────┐     │ │
│  │  │         方法区 (Method Area/MetaSpace)            │     │ │
│  │  │  ┌───────────────────────────────────────────┐  │     │ │
│  │  │  │  - 类信息                                   │  │     │ │
│  │  │  │  - 常量池                                   │  │     │ │
│  │  │  │  - 静态变量                                 │  │     │ │
│  │  │  └───────────────────────────────────────────┘  │     │ │
│  │  └───────────────────────────────────────────────────┘     │ │
│  │                                                            │ │
│  │  ┌───────────────────────────────────────────────────┐     │ │
│  │  │              堆内存 (Heap)                         │     │ │
│  │  │  ┌───────────────────────────────────────────┐  │     │ │
│  │  │  │  新生代                                    │  │     │ │
│  │  │  │    - Eden 区                               │  │     │ │
│  │  │  │    - S0 区                                  │  │     │ │
│  │  │  │    - S1 区                                  │  │     │ │
│  │  │  ├───────────────────────────────────────────┤  │     │ │
│  │  │  │  老年代                                    │  │     │ │
│  │  │  │    - 存活时间长的对象                      │  │     │ │
│  │  │  └───────────────────────────────────────────┘  │     │ │
│  │  └───────────────────────────────────────────────────┘     │ │
│  │                                                            │ │
│  │  ┌───────────────────────────────────────────────────┐     │ │
│  │  │           直接内存 (Direct Memory)                │     │ │
│  │  │  - NIO操作使用的内存                              │     │ │
│  │  └───────────────────────────────────────────────────┘     │ │
│  │                                                            │ │
│  ============================================================= │
│                                                                 │
│  ================== 【线程私有区域】===================         │
│  │                                                            │ │
│  │  ┌───────────────────────────────────────────────────┐     │ │
│  │  │  程序计数器 (PC Register)                           │     │ │
│  │  │  - 存放当前执行指令地址                            │     │ │
│  │  └───────────────────────────────────────────────────┘     │ │
│  │                                                            │ │
│  │  ┌───────────────────────────────────────────────────┐     │ │
│  │  │  虚拟机栈 (JVM Stack)                              │     │ │
│  │  │  ┌───────────────────────────────────────────┐  │     │ │
│  │  │  │  线程1:                                   │  │     │ │
│  │  │  │    - 栈帧1 (方法1)                         │  │     │ │
│  │  │  │    - 栈帧2 (方法2)                         │  │     │ │
│  │  │  │    - ...                                   │  │     │ │
│  │  │  ├───────────────────────────────────────────┤  │     │ │
│  │  │  │  线程2:                                   │  │     │ │
│  │  │  │    - 栈帧1 (方法1)                         │  │     │ │
│  │  │  │    - 栈帧2 (方法2)                         │  │     │ │
│  │  │  │    - ...                                   │  │     │ │
│  │  │  └───────────────────────────────────────────┘  │     │ │
│  │  └───────────────────────────────────────────────────┘     │ │
│  │                                                            │ │
│  │  ┌───────────────────────────────────────────────────┐     │ │
│  │  │  本地方法栈 (Native Method Stack)                  │     │ │
│  │  │  - 为Native方法服务                               │     │ │
│  │  └───────────────────────────────────────────────────┘     │ │
│  │                                                            │ │
│  ============================================================= │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

二、各区域详细说明

1. 堆内存 (Heap) - 线程共享

作用: 存放对象实例和数组

特点:

  • JVM中最大的一块内存区域
  • 被所有线程共享
  • 垃圾回收的主要区域
示例代码:
public class HeapDemo {
    public static void main(String[] args) {
        // 对象1:存储在堆中
        User user1 = new User("张三", 25);
        
        // 对象2:存储在堆中
        User user2 = new User("李四", 30);
        
        // 数组:存储在堆中
        int[] numbers = {1, 2, 3, 4, 5};
        
        // user1, user2, numbers 引用存储在栈中,指向堆中的对象
    }
}

class User {
    private String name;
    private int age;
    
    public User(String name, int age) {
        this.name = name;    // "张三"存储在堆中
        this.age = age;      // 25存储在堆中
    }
}
内存示意图:
栈内存                          堆内存
┌─────────────────────┐        ┌────────────────────────┐
│ main方法栈帧        │        │                        │
│                     │        │  ┌──────────────────┐  │
│ user1 ──────────────┼───────▶│  │ User对象1        │  │
│          [0x1234]    │        │  │  name: "张三"    │  │
│                     │        │  │  age: 25         │  │
│ user2 ──────────────┼───────▶│  └──────────────────┘  │
│          [0x5678]    │        │         [0x1234]        │
│                     │        │                        │
│ numbers ────────────┼───────▶│  ┌──────────────────┐  │
│          [0x9ABC]    │        │  │ User对象2        │  │
│                     │        │  │  name: "李四"    │  │
└─────────────────────┘        │  │  age: 30         │  │
                               │  └──────────────────┘  │
                               │         [0x5678]        │
                               │                        │
                               │  ┌──────────────────┐  │
                               │  │ int[]数组        │  │
                               │  │ [1, 2, 3, 4, 5]  │  │
                               │  └──────────────────┘  │
                               │         [0x9ABC]        │
                               └────────────────────────┘
分代结构:
堆内存
├──────────────────────────────────┐
│         老年代 (Old Generation)   │  存放长期存活的对象
│                                  │  例如:缓存、单例对象
└──────────────────────────────────┘
├──────────────────────────────────┐
│       新生代 (New Generation)    │  存放新创建的对象
│  ┌──────────────────────────┐  │  例如:临时对象、方法局部变量
│  │   Eden 区 (80%)          │  │
│  │  新对象首先进入这里       │  │
│  └──────────────────────────┘  │
│  ┌──────────────┬─────────────┐ │
│  │ Survivor 0   │ Survivor 1  │ │  经过GC后存活的对象
│  │   S0 (10%)   │   S1 (10%)  │ │  在S0和S1之间复制
│  └──────────────┴─────────────┘ │
└──────────────────────────────────┘

2. 方法区 / 元空间 (Method Area / MetaSpace) - 线程共享

作用: 存储类信息、常量、静态变量

特点:

  • Java 8及之前称为"永久代"
  • Java 8之后改为"元空间",使用本地内存
示例代码:
public class MethodAreaDemo {
    
    // 静态变量:存储在方法区
    private static String STATIC_CONFIG = "config_value";
    private static final int MAX_SIZE = 100;
    private static final Map<String, String> CACHE = new HashMap<>();
    
    // 类信息:存储在方法区
    // - 类名、父类、接口
    // - 方法的字节码
    // - 字段信息
    
    public static void main(String[] args) {
        // 字符串常量:存储在方法区的字符串常量池
        String s1 = "hello";
        String s2 = "hello";  // s2和s1指向同一个字符串常量
        
        System.out.println(s1 == s2);  // true,指向同一对象
    }
}
内存示意图:
方法区/元空间
┌─────────────────────────────────────────┐
│  类信息 (Class Metadata)                │
│  ┌─────────────────────────────────┐    │
│  │ MethodAreaDemo类               │    │
│  │  - 类名: MethodAreaDemo         │    │
│  │  - 方法: main()                 │    │
│  │  - 字段: STATIC_CONFIG         │    │
│  └─────────────────────────────────┘    │
│                                          │
│  静态变量                                │
│  ┌─────────────────────────────────┐    │
│  │ STATIC_CONFIG = "config_value"  │    │
│  │ MAX_SIZE = 100                  │    │
│  │ CACHE = HashMap对象引用          │    │
│  └─────────────────────────────────┘    │
│                                          │
│  字符串常量池                             │
│  ┌─────────────────────────────────┐    │
│  │ "hello"  ←──── s1 ─────┐        │    │
│  │                        │        │    │
│  │ "config_value"         │        │    │
│  │                        │        │    │
│  │ "Java"                 │        │    │
│  └────────────────────────┘        │    │
│                                   │    │
└───────────────────────────────────┼────┘
                                    │
                          栈内存     │
                          ┌─────────▼────────┐
                          │ main方法栈帧      │
                          │                  │
                          │ s1 ──────────────┘
                          │                  │
                          │ s2 ──────────────┘
                          │                  │
                          └──────────────────┘

3. 虚拟机栈 (JVM Stack) - 线程私有

作用: 存放方法调用、局部变量、操作数栈

特点:

  • 每个线程都有独立的虚拟机栈
  • 每个方法调用创建一个栈帧
  • 方法执行结束栈帧弹出
示例代码:
public class StackDemo {
    
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int result = add(a, b);
        System.out.println(result);
    }
    
    private static int add(int x, int y) {
        int sum = x + y;
        return sum;
    }
}
内存示意图:
虚拟机栈 (当前线程)
┌────────────────────────────────┐
│  ┌──────────────────────────┐  │
│  │ main方法栈帧               │  │
│  │                           │  │
│  │  局部变量表               │  │
│  │  ┌────────────┐          │  │
│  │  │ args = {}  │          │  │
│  │  │ a = 10     │          │  │
│  │  │ b = 20     │          │  │
│  │  │ result = ? │          │  │
│  │  └────────────┘          │  │
│  │                           │  │
│  │  操作数栈                 │  │
│  │  ┌────────────┐          │  │
│  │  │ [ ]        │          │  │
│  │  └────────────┘          │  │
│  │                           │  │
│  │  返回地址: add方法        │  │
│  └──────────────────────────┘  │
│              ↓                  │
│  ┌──────────────────────────┐  │
│  │ add方法栈帧               │  │
│  │                           │  │
│  │  局部变量表               │  │
│  │  ┌────────────┐          │  │
│  │  │ x = 10     │          │  │
│  │  │ y = 20     │          │  │
│  │  │ sum = 30   │          │  │
│  │  └────────────┘          │  │
│  │                           │  │
│  │  操作数栈                 │  │
│  │  ┌────────────┐          │  │
│  │  │ 30         │          │  │  (x + y的结果)
│  │  └────────────┘          │  │
│  │                           │  │
│  │  返回地址: main方法       │  │
│  └──────────────────────────┘  │
│              ↓                  │
│  ┌──────────────────────────┐  │
│  │ System.out.println栈帧    │  │
│  └──────────────────────────┘  │
└────────────────────────────────┘
栈帧结构:
每个栈帧包含:
┌────────────────────────────┐
│  局部变量表                 │ ← 方法参数、局部变量
│  ─────────────────────────  │
│  操作数栈                   │ ← 方法执行过程中的数据
│  ─────────────────────────  │
│  动态链接                   │ ← 指向运行时常量池
│  ─────────────────────────  │
│  返回地址                   │ ← 方法返回后的执行位置
└────────────────────────────┘

4. 程序计数器 (PC Register) - 线程私有

作用: 存放当前执行的字节码指令地址

特点:

  • 唯一一个没有内存溢出的区域
  • 记录当前线程执行到哪一行字节码
示例说明:
public void example() {
    int a = 10;      // PC指向这条指令
    int b = 20;      // 执行后PC指向下一条
    int c = a + b;   // 继续指向这条指令
    return;          // 最后指向return指令
}
示意图:
线程1的程序计数器          线程2的程序计数器
┌─────────────────┐       ┌─────────────────┐
│ PC = 0x1234     │       │ PC = 0x5678     │
│ (执行main方法)  │       │ (执行其他方法)  │
└─────────────────┘       └─────────────────┘

字节码地址对应:
0x1234: aload_0           // 加载this
0x1235: bipush 10         // 压入10
0x1237: istore_1          // 存储到a
0x1238: bipush 20         // 压入20
0x123A: istore_2          // 存储到b
0x123B: iload_1           // 加载a
0x123C: iload_2           // 加载b
0x123D: iadd              // a + b
0x123E: ireturn           // 返回

5. 本地方法栈 (Native Method Stack) - 线程私有

作用: 为本地方法(native方法)服务

特点:

  • 与虚拟机栈类似
  • 但为Native方法服务
示例代码:
public class NativeDemo {
    
    // 本地方法,调用C/C++代码
    private native void nativeMethod();
    
    // Object类中的native方法示例
    // public native int hashCode();
    // public final native Class<?> getClass();
    
    public static void main(String[] args) {
        NativeDemo demo = new NativeDemo();
        demo.nativeMethod();  // 在本地方法栈中执行
    }
}
内存示意图:
虚拟机栈                    本地方法栈
┌──────────────────┐         ┌──────────────────┐
│ Java方法栈帧     │         │ Native方法栈帧    │
│                  │         │                  │
│ main()           │         │ nativeMethod()   │ ← 调用C代码
│  └─ nativeMethod()├────────┤                  │
│                  │         │ C函数调用栈       │
└──────────────────┘         │  - func1()       │
                             │  - func2()       │
                             └──────────────────┘

6. 直接内存 (Direct Memory) - 线程共享

作用: 避免在Java堆和Native堆之间复制数据

特点:

  • 不受JVM堆内存限制
  • 用于NIO操作
示例代码:
import java.nio.ByteBuffer;

public class DirectMemoryDemo {
    public static void main(String[] args) {
        // 分配直接内存
        ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024); // 1MB
        
        // 这1MB不在Java堆中,而是在直接内存中
        // 优点:减少Java堆和Native堆之间的数据复制
        // 缺点:分配和释放成本较高
    }
}
内存示意图:
JVM堆内存                    直接内存
┌──────────────────┐         ┌──────────────────┐
│ Java对象         │         │ DirectBuffer     │
│                  │         │                  │
│  ┌────────────┐  │         │  ┌────────────┐ │
│  │HeapBuffer  │  │         │  │ 1MB数据    │ │
│  │(堆内缓冲)  │  │         │  │            │ │
│  └────────────┘  │         │  └────────────┘ │
│                  │         │                  │
│  需要复制数据    │         │  直接访问        │
│  到Native堆      │         │  无需复制        │
└──────────────────┘         └──────────────────┘
         ↓                           ↑
    复制操作                        零拷贝

三、完整示例:多线程场景

示例代码:

public class CompleteMemoryDemo {
    
    // 静态变量:存储在方法区
    private static final ConcurrentHashMap<String, String> CACHE = 
        new ConcurrentHashMap<>();
    
    // 实例方法
    public void processData(String input) {
        // 局部变量:存储在栈中
        String processed = input.toUpperCase();
        
        // 创建对象:存储在堆中
        User user = new User(processed);
        
        // 对象引用存储在栈中,对象在堆中
        CACHE.put(input, processed);
    }
    
    public static void main(String[] args) {
        // 主线程
        CompleteMemoryDemo demo = new CompleteMemoryDemo();
        
        // 创建多个线程
        for (int i = 0; i < 3; i++) {
            final int index = i;
            new Thread(() -> {
                demo.processData("data-" + index);
            }).start();
        }
    }
}

class User {
    private String name;
    
    public User(String name) {
        this.name = name;
    }
}

内存分布图:

JVM运行时数据区
┌─────────────────────────────────────────────────────┐
│                    方法区                            │
│  ┌──────────────────────────────────────────────┐  │
│  │ CompleteMemoryDemo类信息                      │  │
│  │  - 方法: processData(), main()               │  │
│  │  - 字段: CACHE                                │  │
│  └──────────────────────────────────────────────┘  │
│                                                     │
│  ┌──────────────────────────────────────────────┐  │
│  │ CACHE = ConcurrentHashMap引用                  │  │
│  │   (实际对象在堆中)                            │  │
│  └──────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│                      堆内存                          │
│  ┌──────────────────────────────────────────────┐  │
│  │ ConcurrentHashMap实例                         │  │
│  │  - "data-0" → "DATA-0"                       │  │
│  │  - "data-1" → "DATA-1"                       │  │
│  │  - "data-2" → "DATA-2"                       │  │
│  └──────────────────────────────────────────────┘  │
│                                                     │
│  ┌────────────┐  ┌────────────┐  ┌────────────┐   │
│  │ User对象1  │  │ User对象2  │  │ User对象3  │   │
│  │ name="DATA │  │ name="DATA │  │ name="DATA │   │
│  │  -0"       │  │  -1"       │  │  -2"       │   │
│  └────────────┘  └────────────┘  └────────────┘   │
└─────────────────────────────────────────────────────┘

┌────────────────────┐  ┌────────────────────┐  ┌────────────────────┐
│   主线程的虚拟机栈   │  │   线程1的虚拟机栈   │  │   线程2的虚拟机栈   │
│  ┌──────────────┐  │  │  ┌──────────────┐  │  │  ┌──────────────┐  │
│  │ main()栈帧    │  │  │  │ run()栈帧     │  │  │  │ run()栈帧     │  │
│  │              │  │  │  │              │  │  │  │              │  │
│  │ demo ────────┼──┼──┼──▶│ processed    │  │  │  │ processed    │  │
│  │              │  │  │  │ index = 0    │  │  │  │ index = 1    │  │
│  │ for循环变量   │  │  │  │ user ────────┼──┼──┼──▶│ user ────────┼──┼────
│  │ i = 0,1,2   │  │  │  │              │  │  │  │              │  │
│  └──────────────┘  │  │  └──────────────┘  │  │  └──────────────┘  │
└────────────────────┘  └────────────────────┘  └────────────────────┘

┌────────────────────┐
│   线程3的虚拟机栈   │
│  ┌──────────────┐  │
│  │ run()栈帧     │  │
│  │              │  │
│  │ processed    │  │
│  │ index = 2    │  │
│  │ user ────────┼────┘
│  │              │  │
│  └──────────────┘  │
└────────────────────┘

每个线程都有独立的:
- 虚拟机栈
- 程序计数器
- 本地方法栈

但共享:
- 堆内存
- 方法区/元空间

四、EscapeObjectProcessor的缓存说明

为什么缓存的不是对象数据?

public class EscapeObjectProcessor {
    
    // 这些缓存存储的是"反射元数据",不是"对象数据"
    private static final ConcurrentHashMap<Class<?>, Field[]> FIELDS_CACHE = new ConcurrentHashMap<>(64);
    private static final ConcurrentHashMap<Class<?>, List<FieldInfo>> ESCAPE_FIELDS_CACHE = new ConcurrentHashMap<>(64);
    private static final ConcurrentHashMap<Class<?>, Boolean> JDK_TYPE_CACHE = new ConcurrentHashMap<>(128);
    
    public void processObject(Object obj) {
        if (obj == null) return;
        
        // 1. 从缓存获取类的字段信息(元数据)
        List<FieldInfo> fieldInfos = getEscapeFields(obj.getClass());
        
        // 2. 遍历字段信息,处理每个对象的数据(动态读取)
        for (FieldInfo fi : fieldInfos) {
            Field field = fi.field;
            field.setAccessible(true);
            
            // 每次都从对象中读取当前值
            String value = (String) field.get(obj);
            
            // 处理值
            String escaped = escapeProcessor.escape(value);
            
            // 写入到对象中
            field.set(obj, escaped);
        }
    }
}

内存分布图:

方法区/元空间 (线程共享)
┌──────────────────────────────────────────┐
│  FIELDS_CACHE (静态变量)                  │
│  ┌────────────────────────────────────┐  │
│  │ User.class ──▶ [name, age, email] │  │  ← 缓存的是"有哪些字段"
│  │                                    │  │
│  │ Order.class ──▶ [id, amount, time]│  │
│  │                                    │  │
│  │ Product.class ──▶ [name, price]   │  │
│  └────────────────────────────────────┘  │
│                                          │
│  ESCAPE_FIELDS_CACHE (静态变量)           │
│  ┌────────────────────────────────────┐  │
│  │ User.class ──▶ [name(带注解)]       │  │  ← 缓存的是"哪些字段需要转义"
│  │                                    │  │
│  │ Order.class ──▶ [amount(带注解)]   │  │
│  └────────────────────────────────────┘  │
│                                          │
│  EscapeObjectProcessor类信息             │
│  - processObject方法                     │
│  - getEscapeFields方法                   │
└──────────────────────────────────────────┘

堆内存 (线程共享)
┌──────────────────────────────────────────┐
│  ┌────────────┐  ┌────────────┐          │
│  │ User对象1   │  │ User对象2   │          │  ← 每个对象的数据是独立的
│  │ name="张三" │  │ name="李四" │          │
│  │ age=25     │  │ age=30     │          │
│  └────────────┘  └────────────┘          │
│                                          │
│  ┌────────────┐  ┌────────────┐          │
│  │ Order对象1  │  │ Order对象2  │          │
│  │ amount=100  │  │ amount=200  │          │
│  └────────────┘  └────────────┘          │
└──────────────────────────────────────────┘

虚拟机栈 - 线程1
┌──────────────────────────────────────────┐
│  processObject方法栈帧                     │
│  ┌────────────┐                          │
│  │ obj ───────┼────────────────────┐      │
│  │            │                    │      │
│  │ fieldInfos ─┼────────────┐     │      │
│  └────────────┘             │     │      │
└─────────────────────────────│─────│──────┘
                              │     │
            从缓存读取元数据  │     │  从堆读取对象当前值
                              │     │
                              ▼     ▼
                      ┌─────────────────┐
                      │ 1. 从缓存获取    │
                      │    FieldInfo[]   │
                      │                 │
                      │ 2. field.get(obj) │ ← 动态读取对象数据
                      │    读取当前值     │
                      │                 │
                      │ 3. 处理数据      │
                      │                 │
                      │ 4. field.set(obj) │ ← 动态写入对象数据
                      │    写入处理结果   │
                      └─────────────────┘

虚拟机栈 - 线程2
┌──────────────────────────────────────────┐
│  processObject方法栈帧                     │
│  ┌────────────┐                          │
│  │ obj ───────┼──────────────────────┐  │
│  │            │                      │  │
│  │ fieldInfos ─┼─────────────────┐   │  │
│  └────────────┘                  │   │  │
└──────────────────────────────────┼───┼──┘
                                   │   │
                    从同一个缓存读取│   │  处理不同的对象
                                   │   │
                                   ▼   ▼
                           ┌───────────────┐
                           │ 处理不同的对象 │
                           │ 各自独立      │
                           └───────────────┘

关键点:

  1. 缓存是元数据FIELDS_CACHE 存储的是"User类有哪些字段",不是"某个User对象的字段值是什么"

  2. 数据是动态的:每次调用 field.get(obj) 都会从堆内存中读取对象当前的值

  3. 线程安全

    • 每个线程有独立的虚拟机栈
    • 每个方法的参数 obj 是独立的(存储在各自线程的栈中)
    • 虽然多个线程可能同时读取同一个缓存,但缓存本身是只读的(获取后不会修改)
  4. 内存隔离

    线程1的obj ──▶ User对象1 (name="张三", age=25)
    线程2的obj ──▶ User对象2 (name="李四", age=30)
    
    两个线程共享:
    - FIELDS_CACHE (类的元数据)
    
    但各自独立:
    - 自己的栈帧
    - 自己的obj参数
    - 各自处理不同的对象数据
    

五、常见问题

Q1: 为什么静态变量在方法区而不是栈?

A: 静态变量属于类,不属于方法。类的所有实例共享静态变量,所以放在线程共享的方法区。

Q2: 字符串常量为什么在方法区?

A: 为了避免重复创建相同的字符串,JVM在方法区维护一个字符串常量池,所有"hello"字面量都指向同一个对象。

Q3: 栈溢出和堆溢出有什么区别?

A:

  • 栈溢出 (StackOverflowError): 递归太深,栈帧超过了虚拟机栈的深度限制
  • 堆溢出 (OutOfMemoryError): 对象太多,堆内存不足

Q4: 为什么方法区改为元空间?

A: Java 8之前使用永久代,容易因为类加载过多导致内存溢出。改为元空间使用本地内存,可以动态调整,避免OOM。

Q5: 直接内存有什么用?

A: 主要用于NIO操作,可以避免在Java堆和Native堆之间复制数据,提高IO性能。


六、总结

内存区域 线程共享/私有 存储内容 常见异常
堆内存 共享 对象实例、数组 OutOfMemoryError
方法区 共享 类信息、常量、静态变量 OutOfMemoryError
虚拟机栈 私有 方法调用、局部变量 StackOverflowError
程序计数器 私有 当前执行指令地址
本地方法栈 私有 Native方法调用 StackOverflowError
直接内存 共享 NIO缓冲区 OutOfMemoryError

关键要点:

  1. 线程共享区域:堆内存、方法区、直接内存 - 需要考虑线程安全
  2. 线程私有区域:虚拟机栈、程序计数器、本地方法栈 - 天然线程安全
  3. 缓存策略:EscapeObjectProcessor缓存的是反射元数据(类的结构),不是对象数据(字段值)
  4. 参数隔离:每个方法调用有独立的栈帧,参数互不干扰
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐