Java虚拟机(JVM)内存结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38737992/article/details/89429979

1. 概述

Java虚拟机(JVM)执行程序时会将管理的内存分为若干个不同的数据区域,分别为程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Stack)、堆(Heap)、方法区(Method Area)。

线程共享的数据区:堆(Heap)、方法区(Method Area)。

线程私有的数据区:程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Stack)。

其中堆(Heap)分配的内存最大。

2. 程序计数器

程序计数器(Program Counter Register)分配的内存较小、线程私有(多个线程相互不影响,独立存储)。

作用:当前线程所执行的字节码的行号指示器,字节码解释器是通过改变这个值来选取下一条要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等需要这个计数器。

如果线程正在执行的是Java方法,计数器记录的就是正在执行的虚拟机字节码指令的地址。

如果是Native方法,则计数器为空(Undefined)。

3. Java 虚拟机栈

Java 虚拟机栈,线程私有,生命周期和线程相同。

虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,对应一个栈帧在虚拟机栈中的入栈到出栈的过程。

局部变量表,存放了编译期间可知的各种基本数据类型(char、byte、short、int、long、float、double、boolean)、对象引用(引用类型、不等同与对象本身,可能是指向对象起始地址的一个指针,也可能是一个代表对象的句柄或其他与此对象有关的位置)、returnAddress类型(一条字节码指令的地址)。

64 位的long和double类型的数据会占用2个局部变量空间(Slot),其余数据类型只占一位。

局部变量表的内存空间大小在编译期间完成分配,运行时不会改变。

线程请求的栈深度大于虚拟机允许的深度时,抛出StackOverflowError异常。

虚拟机栈动态扩展时申请不到足够的内存,会抛出OutOfMemoryError异常。

4. 本地方法栈

和虚拟机栈的作用相似,区别本地方法栈是为虚拟机使用到的Native方法服务。

会抛出StackOverflowError异常和OutOfMemoryError异常。

5. Java 堆

Java虚拟机管理的内存中最大的一块,所有线程共享,虚拟机启动时创建。

唯一目的:存放对象实例,所有的对象实例和数组都要在堆上分配内存。

Java 堆是垃圾收集器管理的主要内存区域,所以别名“GC堆”。

Java 可以在物理上不连续,只要逻辑是连续的就像我们的磁盘一样。

可以固定大小,也可以是可扩展的。

动态扩展时申请不到足够的内存,会抛出OutOfMemoryError异常。

6. 方法区

所有线程共享、存储虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。

除了和堆一样,物理上可以不连续,只要逻辑是连续的就像我们的磁盘一样。可以固定大小,也可以是可扩展的,还可以选择不实现垃圾收集。

方法区中的垃圾收集行为出现较少,这个区域的垃圾回收主要是针对常量池的回收和对类型的卸载。

运行时常量池,方法区的一部分,用于存放编译期间生成的各种字面量和符号引用,这部分内容在类加载后进入方法区的运行时常量池存放。

运行时常量池具有动态性,不要求常量一定在编译期间产生,运行时也可以将新的常量放入池中,例如String类的intern。

动态扩展时申请不到足够的内存,会抛出OutOfMemoryError异常。

猜你喜欢

转载自blog.csdn.net/qq_38737992/article/details/89429979