JVM(一):Run-Time Data Areas(运行时数据区)/ 内存区域

一:前言

特别说明:文章中引用的图片是通过谷歌的方式找到的,当时并没有找到图片是否拥有版权,如果遇到了的话,请告知博主,我会将相应的图片删除。

本博客主要总结的是JVM的Run Time Data Areas(运行时数据区),也就是我们常说的内存区域。借用Inside Java Virtual Machine里的一句话来说明一下这一块内容。

When a Java virtual machine runs a program, it needs memory to store many things, including bytecodes and other information it extracts from loaded class files, objects the program instantiates, parameters to methods, return values, local variables, and intermediate results of computations. The Java virtual machine organizes the memory it needs to execute a program into several runtime data areas.

上面这句话的意思是:运行时数据区就是存储二进制代码、类文件信息、程序对象的实力、方法参数、返回值、本地变量、计算结果等的一块内存区域。
为了方便大家的阅读,在后面的片段中,我会将运行时数据区称为内存区域(毕竟这是大家习惯也更愿意这样说的称呼,前者更像是JVM规范中的一种说法)。

二:结构

JVM(一):Run-Time Data Areas(运行时数据区)/ 内存区域_第1张图片

如上所示就是JVM内存分布的结构图,在JVM规范中其实只说明了上半部分的构成,直接内存是Java加上NIO后才出现的一块内容,具体的内容将在后续内容中说明。如果我们将每个区的内容再细化一下,那么就会得到如下一章内存分布图。
JVM(一):Run-Time Data Areas(运行时数据区)/ 内存区域_第2张图片

三:内容详解

3.1 程序计数器

属性 内容
英文名称 Programmer Counter Register / PC Register
作用 保存当前线程执行的行号指示器(内存地址)
作用域 线程私有(每个线程都拥有一个这样的程序计数器)
大小 一个字长
生命周期 与所处线程的生命周期一样
存储内容 1:如果执行的是Java方法,那么将会记录正在执行的字节码指令。2:如果执行的Native方法,那么将会为空。3:Return Address.
异常 不抛出异常
特别说明 JVM是通过线程轮流切换并分配处理器的执行时间的方式来实现的,所以需要一个能够记录各个线程执行的代码的位置的容器,也就是我们的程序计数器

3.2 Java虚拟机栈

属性 内容
英文名称 Java Virtual Machine Stack / JVM Stack
作用 存储方法在运行过程中所需的数据信息;并且在方法的调用和返回上发挥着重要的作用
作用域 线程私有(每个线程都拥有一个这样的程序计数器)
大小 可以通过配置,设置该栈的为固定大小也可以设置栈的最小最大值。
基本单位 栈帧(Stack Frame)
生命周期 与所处线程的生命周期一样
存储内容 存储的基本单元是栈帧(Stack Frame),运行一个方法就会产生一个栈帧,栈帧就包含运行时所需的一些数据信息。从概念上分,栈帧中包含局部变量表(Local Variables)、操作数栈(Operand Stack)、动态链接(Dynamic Linking)、方法返回地址(Return Address)以及一些其它的信息(例如我们的调试信息也会存在与这个部分)
异常 1:StackOutOfMemoryError发生在一个线程中当单个栈的限定内存不能够满足用户在运行过程中所需的内存那么就会抛出该异常。2:OutOfMemoryError发生在当用户创建多个线程的时候,由于每个线程都有最低内存设置,当我们的内存不能够满足我们创建指定个数的线程的时候就会抛出内存溢出异常

3.2.1 本地变量表

属性 内容
英文名称 Local Variables
作用 存储方法中的变量信息
作用域 栈帧私有,不同的栈帧之间不可以相互调用
生命周期 调用方法时候创建,方法执行完毕销毁
存储内容 一个包含方法中变量的数组;方法参数、方法变量
基本单位 变量槽(Variable Slot)
数据类型 1:一个导向槽可以存储byte、boolean、char、short、int、float、reference、returnAddress。2:long、double需要两个导向槽。
注意事项 1:对于非静态变量方法,局部变量表的第一个值存储的是方法所在对象的引用(也就是我们常说的this);而对于静态变量方法则没有。2:局部变量表的大小在编译的时候已经确定,这个信息就存在方法区中。3:byte、char、short会在存储的时候被自动转换为int类型。

3.2.2 操作数栈

属性 内容
英文名称 Operand Stack
作用 记录方法在运行的过程中用到的变量
数据结构 先进后出的栈
生命周期 调用方法时候创建,方法执行完毕销毁
存储内容 记录在方法运行过程中需要用到的变量的值,所有值的调用都是通过指令集将对应的变量添加到操作数栈,然后再调用
基本单位 变量槽(Variable Slot)
注意事项 1:大小在编译的时候已经确定,这个信息就存在方法区中。

3.2.3 动态链接

属性 内容
英文名称 Dynamic Linking
作用 一般的解析都是静态解析,通过这个我们可以实现动态解析,当运行到某一块代码的时候再进行解析运行
生命周期 调用方法时候创建,方法执行完毕销毁
特别说明 由于每个栈帧对记录的有一个当前栈帧在运行时常量池中的引用,所以可以通过这个引用帮我们实现动态链接相关的操作

3.2.4 方法返回地址

属性 内容
英文名称 Return Address
作用 记录当前方法的执行结果
内容 1:当方法正常执行的时候,记录的是一个代表运行结果的字节码,常被称为Normal Method Invocation Completion。2:当方法出现异常的时候,返回的是一个来自异常表中的异常,这种常被称为Abrupt Method Invocation Completion。

3.2.5 其它信息

这其它信息中比较常见的一项就是调试(debugger)的信息、常量池的引用信息等。有些信息根据虚拟机的不同会有不同的变化。

3.2.6 结语

如果我们对这个进行分的的话,我们会发现,这个区域主要是记录相应的内容,而并未涉及到相应的调用操作,而执行的具体操作也就是push和pop,所以从这点上来看,我们在实现这块内容的时候,不仅可以使用栈的技术,也可以使用堆来创建。

3.3 Native 方法栈

在结构上和Java虚拟机栈是一样的,只是说调用的方法可能会不同,前者调用的都是Java方法,而Java虚拟机栈则是调用的Native方法。由于结构都是一样的这里就不再作进一步的说明了。

3.4 Java堆

属性 内容
英文名称 Java Heap
作用 记录所有的实例化对象的信息以及数组的信息
作用域 所有线程共享
生命周期 在JVM开启时创建,对象的堆内存由在GC的时候被销毁,整个堆的消失实在JVM关闭的时候
大小 既可以固定大小也可以配置大小的上下线
注意事项 1:由于堆的内存是共享的,所以不同线程调用堆中相同的信息,这也是锁出现的原因。2:Java只提供了分配内存的命令,并没有提供销毁内存的命令,所以需要GC来控制
构成 1:如果使用的是分代算法,那么就分为新生代、老生代。具体来说就是:Eden空间、From Survivor空间、To Survivor空间
优化 虽然所示所有线程共享堆,但是可以通过做特定的操作,来优化GC的效率,比如说设置TLAB:Thread Local Allocation Buffer
异常 当用户设定的容量不满足程序所需的容量的时候,会抛出OutOfMemoryError

3.5 方法区

属性 内容
英文名称 Method Area
作用 存储每个类的结构
作用域 所有线程共享
生命周期 在JVM开启时创建,部分内容在GC的时候被销毁,整个的消失实在JVM关闭的时候
大小 既可以固定大小也可以配置大小的上下线
构成 运行时常量池、字段信息、方法信息、所有的静态变量、Class Loader的引用、Class的引用等
异常 当用户设定的容量不满足程序需求的容量的时候,会抛出OutOfMemoryError

3.5.1 运行时常量池

属性 内容
英文名称 Run Time Constant Pool
作用 存储编译时期的字面量以及符号引用
作用域 所有线程共享
生命周期 在JVM开启时创建,部分内容在GC的时候被销毁,整个的消失实在JVM关闭的时候
大小 既可以固定大小也可以配置大小的上下线
注意事项 Java语言要求常量不一定在编译期才能使用,运行的时候一样也可以将新的常量放入常量池,比如String.intern()

3.5.2 类型信息

属性 内容
英文名称 Type Information
作用 存储类或者接口的相关信息,比如:标识符,父类或者父接口的全名,类的全名
作用域 所有线程共享
生命周期 在JVM开启时创建,部分内容在GC的时候被销毁,整个的消失实在JVM关闭的时候
大小 既可以固定大小也可以配置大小的上下线

3.5.3 字段信息

属性 内容
英文名称 Field Information
作用 记录字段的数据相关信息:名字、类型、标识符
作用域 所有线程共享

3.5.4 方法信息

属性 内容
英文名称 Method Information
作用 记录字段的方法相关信息
作用域 所有线程共享
存储内容 1:方法的名字,标识符,返回值。2:局部变量表、操作数栈的大小。3:方法参数的类型和数量。4:方法的二进制代码

3.5 直接内存

本地内存的出现是自Java中添加了NIO之后才有的,NIO引入了一个基于通道/缓存的I/O方式,可以使用Native函数直接在对外分配内存,这样就避免了Java堆和Native堆的相互调用了,提升了访问速度。这块,也是抛出OutOfMemoryError异常的。


你可能感兴趣的:(Java)