Java 运行时数据区
Java 运行时数据区主要包括以下几个部分:
- 程序计数器(Program Counter Register):
- 是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。
- 每个线程都有一个独立的程序计数器,线程私有,此区域不会出现内存溢出异常。
- Java 虚拟机栈(Java Virtual Machine Stacks):
- 描述的是 Java 方法执行的内存模型。
- 每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
- 线程私有,如果线程请求的栈深度大于虚拟机所允许的深度,将抛出
StackOverflowError
异常;如果虚拟机栈可以动态扩展,但扩展时无法申请到足够的内存,会抛出OutOfMemoryError
异常。
- 本地方法栈(Native Method Stacks):
- 与虚拟机栈的作用类似,只不过本地方法栈为虚拟机使用到的 Native 方法服务。
- 同样线程私有,也可能抛出
StackOverflowError
和OutOfMemoryError
异常。
- Java 堆(Java Heap):
- 是被所有线程共享的一块内存区域,几乎所有的对象实例以及数组都在这里分配内存。
- 如果堆中没有足够的内存完成实例分配,并且堆也无法再扩展时,将会抛出
OutOfMemoryError
异常。
- 方法区(Method Area):
- 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- 当方法区无法满足内存分配需求时,会抛出
OutOfMemoryError
异常。
- 运行时常量池(Runtime Constant Pool):
- 是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。
- 当常量池无法再申请到内存时会抛出
OutOfMemoryError
异常。
例如,如果在一个 Java 程序中,不断创建大量的对象并且不进行垃圾回收,最终可能导致堆内存溢出:
public class HeapOverflowExample { public static void main(String[] args) { List<Object> list = new ArrayList<>(); while (true) { list.add(new Object()); } } }
当运行上述代码时,很快就会出现 OutOfMemoryError
异常。
再比如,如果一个方法递归调用次数过多,可能会导致栈溢出:
public class StackOverflowExample { public static void main(String[] args) { recursiveMethod(); } public static void recursiveMethod() { recursiveMethod(); } }
运行这段代码,会抛出 StackOverflowError
异常。