Java虚拟机中内存分配

161 阅读6分钟
Java运行时的内存分为五大部分,分别为方法区、堆、虚拟机栈、本地方法栈、程序计数器,其中方法区以及堆是属于所有线程共享的内存,而虚拟机栈、本地方法栈、和程序计数器是属于线程私有的内存。这些内存统一由虚拟机分配。
1.程序计数器(PCR)
程序计数器:是一块较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器,标识这当前程序运行的位置。在虚拟机概念模型中(仅仅是概念模型中,不同的虚拟机可能会通过更高效的方式实现),字节码解释器就是通过修改程序计数器中的值来选择下一条要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。
由于java虚拟机的多线程是通过线程的轮流切换完成的,那么就需要一个线程有一个自己的程序计数器来记录当前线程执行的位置,方便线程切换的时候恢复各自线程的程序执行。所以对于程序计数器来说是每个线程所独有的,不能被共享的。
程序计数器还有一个特点就是不会有OutOfMemoryError的情况,因为保存的就是当前程序所执行的字节码文件的地址(也就是行号),并没有保存有大量的数据,因此不会出现OOM的问题。同时程序计数器只是记录当前java代码的字节码执行的位置,并不会去记录native字节码的执行位置。也就是说当程序执行的方法是native方法的话,程序计数器所记录的数据是空(Undefined)。
ps:感觉这个里面的程序计数器跟计算机体系中的程序计数器有这异曲同工的作用。以下是计算机中的程序计数器的定义:程序计数器(PC)是用于存放下一条指令所在单元的地址的地方。程序计数器是计算机处理器中的寄存器,它包含当前正在执行的指令的地址(位置)。当每个指令被获取,程序计数器的存储地址加一。在每个指令被获取之后,程序计数器指向顺序中的下一个指令。当计算机重启或复位时,程序计数器通常恢复到零。
2.虚拟机栈
虚拟机栈是线程私有的,生命周期与线程相同。虚拟机栈描述的是Java方法的内存模型:每个方法在执行的时候会创建一个栈桢用于存储局部变量表、操作数栈、方法出口、动态链接等相关信息。
局部变量表存放的是编译期的基本数据类型以及对象引用和returnAddress(一条字节码指令的地址),其中数据类型如果是64位的long或者是double的话占的是两个局部空间,其余的占的是1个局部空间。
在java中如果线程请求的栈的深度大于虚拟机所能分配的最大深度则会跑出StackOverFlowError的错误,还有就是在虚拟机栈动态扩展的时候没有足够的内存的话则会抛出OutOfMemoryError的问题。
3.本地方法栈
本地方法栈与虚拟机栈的功能一样都是为方法进行服务的一个是为Java方法进行服务,一个是为native方法进行服务的。同时也会出现虚拟机栈出现的两种异常情况。
4.java堆
Java堆是虚拟机分配的最大的一块内存,其中主要存放的是对象的实例。是虚拟机中所有线程共享的。同时也是jvm垃圾回收处理的主要部位。在虚拟机进行分配的时候堆内存的物理地址可以是连续的也可以是不连续的,只要在逻辑上连续的就可以。同时进行分配的时候也可以是固定大小或者是可以扩展的,目前主流的虚拟机分配堆内存的时候都是以可扩展的方式进行分配的,这样用户可以自己设定堆的大小及堆的最大大小(通过Xmx和Xms进行控制)。当堆内的对象不能实例化,并且堆不能继续扩容的时候会抛出OutOfMemoryError的异常。
5.方法区
方法区是各个线程共享的内存区域。它用于存储已被虚拟机加载的类的信息、常量、静态变量、即时编译器编译后的代码等数据。同时具有和堆一样不需要连续内存可以选择固定大小或者可扩展以外,还可以选择不实现垃圾收集。其实不实现垃圾收集的主要原因是因为方法区中的数据在垃圾回收时效果不是那么的满意,并且在进行垃圾回收的时候主要回收的是该区域的常量以及对类型的卸载。在对类型的卸载过程中很难判断是否可以回收。但是不是说就不需要对该区域进行垃圾回收了。因为方法区也会出现OutOfMemoryError的问题。
6.运行时常量池(这个是方法区的一部分)
用于存放编译期生成的各种字面常量和符号引用,这些内容是在类加载之后进入到运行时常量池中的。一般来说这个运行时常量池不单纯存储Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储到运行时常量池中。
运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不 要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方 法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较 多的便是String类的intern()方法。
同时运行时常量池也会出现OutOfMemoryError的问题。

参考文献:

深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)--周志明