栈、堆、方法区

Java 运行时数据区 - 总览

Java 虚拟机(JVM)在运行 Java 程序时管理一块内存区域,称为运行时数据区。根据《Java 虚拟机规范》,它分为多个部分,各有特定作用。

运行时数据区
线程私有
线程共享
Java 虚拟机栈
本地方法栈
程序计数器
方法区

1. Java 虚拟机栈

定义与特性

Java 虚拟机栈(Java Virtual Machine Stack) 是 JVM 用于管理方法调用的内存区域,采用栈式数据结构(先进后出,FILO)。每个方法调用创建一个栈帧(Stack Frame)

  • 生命周期:随线程创建而创建,随线程销毁而回收。
  • 线程私有:每个线程拥有独立栈。
线程 1
虚拟机栈 1
线程 2
虚拟机栈 2
栈帧 1
栈帧 2
栈帧 3

栈帧的组成

1.1 局部变量表

  • 作用:存储方法运行时的局部变量。
  • 结构:数组形式,每个元素为槽(Slot)
    • longdouble 占用 2 个槽。
    • 其他类型占用 1 个槽。
  • 内容
    • 实例方法第 0 槽存储 this
    • 方法参数按声明顺序存储。
    • 方法体内局部变量。
  • 优化:槽可复用。
局部变量表
+Slot[1]: 参数 1
+Slot[2]: 参数 2
+Slot[0]: this(实例方法)
+Slot[3]: 局部变量(可复用)

1.2 操作数栈

  • 作用:临时存储指令执行的数据。
  • 特性:栈式结构,编译期确定最大深度。
压入
压入
弹出
操作数栈
值 1
值 2
指令使用

1.3 帧数据

  • 动态链接:符号引用转为运行时常量池地址。
  • 方法出口:记录返回地址。
  • 异常表:存储异常处理信息。
帧数据
动态链接
方法出口
异常表
符号引用 -> 内存地址
返回调用者指令
异常范围 + 跳转地址

栈内存溢出

  • 原因:栈帧过多,超出容量。
  • 异常StackOverflowError

示例代码

public class StackOverflowTest {
    public static int count = 0;
    public static void recursion() {
        System.out.println(++count);
        recursion(); // 递归调用导致溢出
    }
    public static void main(String[] args) {
        recursion();
    }
}

设置栈大小

  • 参数-Xss<大小>-XX:ThreadStackSize=<大小>
  • 单位:字节(需为 1024 倍数)、k/K(KB)、m/M(MB)、g/G(GB)。
  • 限制(HotSpot JVM):
    • Windows 64 位,JDK 8:最小 180KB,最大 1024MB。
  • 建议-Xss256k 节省内存。

2. 本地方法栈

  • 作用:管理 native 本地方法的栈帧。
  • 实现:HotSpot 中与 Java 虚拟机栈共用空间。
栈空间
Java 虚拟机栈
本地方法栈
Java 方法栈帧
native 方法栈帧

3. 堆

定义与特性

堆(Heap) 是 JVM 最大内存区域,存储对象实例

  • 线程共享:通过引用(如局部变量或静态变量)访问。
  • 关键指标
    • used:已使用内存。
    • total:已分配可用内存。
    • max:最大可用内存。
  • 默认值
    • max:系统内存 1/4。
    • total:系统内存 1/64。
增长
扩展
used
total
max

设置堆大小

  • 参数
    • -Xms<大小>:初始堆大小。
    • -Xmx<大小>:最大堆大小。
  • 单位:字节(需为 1024 倍数)、k/Km/Mg/G
  • 建议-Xms-Xmx 设为相同值,避免频繁调整。

4. 方法区

定义与作用

方法区(Method Area) 是线程共享区域,存储类信息和常量。

核心组成部分

  1. 类的元信息
    • 存储类的结构(如 InstanceKlass)。
InstanceKlass
+字段信息
+方法信息
+类名
  1. 运行时常量池
    • 将静态常量池转为直接引用。
解析
字节码常量池
运行时常量池
符号引用 #1
内存地址
  1. 字符串常量池
    • 存储字符串常量。
字符串常量池
+"Hello"
+"World"

方法区溢出

  • JDK 7:位于永久代(PermGen),用 -XX:MaxPermSize 控制。
  • JDK 8+:移至元空间(Metaspace),默认无上限,可用 -XX:MaxMetaspaceSize 限制。
JDK 7
堆 - 永久代
JDK 8+
元空间 - 直接内存
-XX:MaxPermSize
-XX:MaxMetaspaceSize

5. ByteBuddy 框架简介

ByteBuddy 是用于动态生成和操作 Java 字节码的库。

使用步骤

  1. 引入依赖(Maven):
    <dependency>
        <groupId>net.bytebuddy</groupId>
        <artifactId>byte-buddy</artifactId>
        <version>1.14.12</version>
    </dependency>
    
  2. 生成字节码
    import net.bytebuddy.ByteBuddy;
    import net.bytebuddy.implementation.FixedValue;
    import static net.bytebuddy.matcher.ElementMatchers.named;
    
    public class ByteBuddyExample {
        public static void main(String[] args) throws Exception {
            Class<?> dynamicType = new ByteBuddy()
                .subclass(Object.class)
                .method(named("toString"))
                .intercept(FixedValue.value("Hello, ByteBuddy!"))
                .make()
                .load(ByteBuddyExample.class.getClassLoader())
                .getLoaded();
            System.out.println(dynamicType.newInstance().toString());
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王嘉俊925

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

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

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

打赏作者

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

抵扣说明:

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

余额充值