← 返回首页
🧠

JVM内存模型详解:堆、栈与方法区

📂 java ⏱ 2 min 350 words

JVM内存模型详解:堆、栈与方法区

概述

JVM内存模型是Java程序运行的基础。理解内存模型对于性能调优和问题排查至关重要。

1. JVM内存区域

public class JVMMemoryDemo {
    // 类变量(方法区)
    private static int classVar = 100;
    
    // 实例变量(堆)
    private int instanceVar = 200;
    
    public void method() {
        // 局部变量(栈)
        int localVar = 300;
        
        // 对象引用(栈),对象本身(堆)
        String str = new String("Hello");
        
        System.out.println("类变量: " + classVar);
        System.out.println("实例变量: " + instanceVar);
        System.out.println("局部变量: " + localVar);
    }
    
    public static void main(String[] args) {
        JVMMemoryDemo demo = new JVMMemoryDemo();
        demo.method();
        
        // 打印内存信息
        Runtime runtime = Runtime.getRuntime();
        System.out.println("最大内存: " + runtime.maxMemory() / 1024 / 1024 + " MB");
        System.out.println("总内存: " + runtime.totalMemory() / 1024 / 1024 + " MB");
        System.out.println("可用内存: " + runtime.freeMemory() / 1024 / 1024 + " MB");
    }
}

2. 堆内存

public class HeapMemoryDemo {
    public static void main(String[] args) {
        // 堆内存分为:
        // 1. 新生代(Young Generation)
        //    - Eden区:新对象分配在这里
        //    - Survivor区(S0, S1):经过GC存活的对象
        // 2. 老年代(Old Generation):长期存活的对象
        
        // 创建大量对象,触发GC
        for (int i = 0; i < 100000; i++) {
            byte[] array = new byte[1024];
        }
        
        System.gc();  // 建议JVM进行垃圾回收
        
        // 查看GC日志
        // -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
    }
}

3. 栈内存

public class StackMemoryDemo {
    // 栈帧包含:局部变量表、操作数栈、动态链接、方法返回地址
    
    public static void recursiveMethod(int n) {
        if (n == 0) {
            return;
        }
        recursiveMethod(n - 1);  // 每次调用创建新的栈帧
    }
    
    public static void main(String[] args) {
        try {
            recursiveMethod(10000);  // 可能导致StackOverflowError
        } catch (StackOverflowError e) {
            System.out.println("栈溢出: " + e.getMessage());
        }
    }
}

4. 方法区

public class MethodAreaDemo {
    // 方法区存储:类信息、常量、静态变量、JIT编译后的代码
    
    // 常量池
    private static final String CONSTANT = "Hello";
    
    // 静态变量
    private static int staticVar = 100;
    
    // 类信息
    public void method() {
        // 运行时常量池
        String str = "World";
    }
    
    public static void main(String[] args) {
        // 查看类加载信息
        Class<?> clazz = MethodAreaDemo.class;
        System.out.println("类名: " + clazz.getName());
        System.out.println("类加载器: " + clazz.getClassLoader());
    }
}

5. 内存分配策略

public class MemoryAllocationDemo {
    // 对象优先在Eden区分配
    // 大对象直接进入老年代
    // 长期存活的对象进入老年代
    // 动态对象年龄判断
    
    private static final int _1MB = 1024 * 1024;
    
    public static void main(String[] args) {
        // 测试对象优先在Eden区分配
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[2 * _1MB];
        allocation2 = new byte[2 * _1MB];
        allocation3 = new byte[2 * _1MB];
        
        // 出现一次Minor GC
        allocation4 = new byte[4 * _1MB];
    }
}

6. 最佳实践

  1. 合理设置堆大小:-Xms和-Xmx参数
  2. 监控内存使用:使用jstat、jmap等工具
  3. 避免内存泄漏:及时释放不再使用的对象
  4. 优化对象创建:使用对象池、缓存等技术
  5. 选择合适的GC算法:根据应用场景选择

总结

JVM内存模型是Java程序运行的基础。理解堆、栈、方法区的作用和内存分配策略,对于性能调优和问题排查至关重要。