引言
java虚拟机在执行的过程中会把他所管理的内存划分为若干个不同的数据区域。一是方便管理,二是方便回收,针对不同区域的数据进行不同算法的垃圾处理机制。
程序计数器
- 概念
程序计数器是一块较小的内存空间,它可以看成是当前线程执行的字节码的行号指示器。字节码解释器在工作的时候就要通过改变这个计数器的值来选取下一条需要执行的字节码指令。比如分支,循环,跳转,线程处理乱七八糟的。
简单来说,程序计数器为指令提供了执行的顺序。 - 特点
每条线程都有一个独立的程序计数器,各条线程之间的程序计数器互不影响,独立储存。我们称这类内存区域是“线程私有”的内存。且此内存区域是唯一一个没有规定任何OutOfMemoryError的区域。
(1)线程私有
(2)线程开始执行的时候创建
(3)因为是保存的字节码的地址,所以调用NATIVE方法的时候,计数器的值是undefined。
(4)程序计数器保存的是当前执行的字节码的偏移地址,当执行到下一条指令的时候,改变的只是程序计数器中保存的地址,并不需要申请新的内存来保存新的指令地址;因此,永远都不可能内存溢出的。
Java虚拟机栈
- 概念
虚拟机栈描述的是JAVA方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧。这个栈帧存储了局部变量表,操作数栈,动态链接,方法出口等信息。且,每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈和出栈的过程 - 虚拟机栈的特点
(1)线程私有
(2)后进先出栈
(3)两种异常 - 局部变量表介绍
(1)局部变量表存放了编译期可知的各种基本数据类型,对象引用,和一条字节码指令的地址
(2)局部变量表所需要的内存空间在编译期间完成分配,一个方法的运行期间不会改变局部变量表的大小。 - 虚拟机栈的两种异常
(1)如果线程请求的栈深度,大于虚拟机所允许的深度,将抛出StackOverFlowError异常。
(2)在可以动态拓展的虚拟机中,如果无法申请足够的内存,就会抛出OutOfMemeryError异常。
本地方法栈
本地方法栈是为Native方法服务的内存模型。其他的特点与Java方法栈一致,有些虚拟机的设计中,将本地方法栈和JAVA方法栈合二为一了。
- 本地方法栈的特点
(1)线程私有
(2)后进先出栈
(3)两种异常
JAVA堆
- 概念
JAVA堆是被所有线程共享的一块区域,在虚拟机启动时创建。这个内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。 - 特点
(1)线程共享。
(2)是垃圾回收器管理的主要区域。
(3)可以处于物理上不连续的内存空间中。
(4)如果堆内存空间不够实例对象的分配,将抛出OutOfMemeryError异常。
方法区
方法区用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。其实是堆的逻辑的一部分,但是为了区别,又叫座non-heap(非堆)。
(1)线程共享。
(2)是垃圾回收器管理的次要区域。
(3)可以处于物理上不连续的内存空间中。
(4)如果堆内存空间不够实例对象的分配,将抛出OutOfMemeryError异常。
运行时的常量池
运行时的常量池是方法区的一部分。一般来说保存的是CLASS文件中描述的符号引用,以及翻译出来的直接引用。但是JVM规范没有做任何的细节要求,意味着厂商可以根据自己的需要来实现这块内存区域。
运行时常量池。
运行时常量池相比于Class文件常量池的另外一个重要特征是具备动态性, Java语言并不要求常量一定只有编译期才能产生,运行期间也能将新的常量放到常量池中。这种特性被开发人员用的比较多的是String的intern()方法。
各个模块的图示
总结
这里需要注意几点问题:
- 常量池(Constant Pool): 常量池数据编译器被确定,是class文件中的一部分,存储了类,方法,接口等中的常量,当然也包括字符串常量。
常量池:可以理解为Class文件之中的资源仓库,它是Class文件结构中与其他项目资源关联最多的数据类型
常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic Reference)。
字面量:文本字符串、声明为final的常量值等;
符号引用:类和接口的完全限定名(Fully Qualified Name)、字段的名称和描述符(Descriptor)、方法的名称和描述符 - 字符串池/字符串常量池(String Pool/String Constant Pool):是常量池中的一部分,存储了编译器产生的字符串类型数据
- 运行时常量池(Runtime Constant Pool): 方法区的一部分,所有线程共享。虚拟机加载class文件后把常量池中的数据存放到运行时常量池中
这里需要注重提一下在JDK1.6之前字符串常量池是存在于方法区之中,在JDK1.7和以上字符串常量池存在了堆之中。
这是官网翻译后的中文说明:在JDK 7中,在Java堆的永久生成中不再分配interned字符串,而是在Java堆的主要部分(称为young和old generation)中分配,以及应用程序创建的其他对象。此更改将导致更多的数据驻留在主Java堆中,而在永久生成中数据更少,因此可能需要调整堆大小。由于这种变化,大多数应用程序在堆使用上只会看到相对较小的差异,但是更大的应用程序加载了许多类,或者大量使用了string . intern()方法将看到更显著的差异。
作者:select you from me
来源:优快云
转载请联系作者获得授权并注明出处。