引言:Java虚拟机在执行Java程序的过程中,会把它管理的内存划分为若干个数据区域。这些区域有各自的特点与用途。以下是简图
一,这些数据区域分为两类
1,线程隔离的数据区:这些区域则是依赖用户线程的启动和结束而建立和销毁。
包括:程序计数器,Java虚拟机栈,本地方法栈
特点:Java垃圾回收机制并不关注这个三个区,因为随着线程的结束,内存自然就随着被回收了
2,由所有线程共享的数据区:这些区域随着虚拟机进程的启动而存在。
包括:方法区,堆
特点:Java中的垃圾收集器所关注的就是线程隔离的数据区,即方法区和堆。
二,JVM运行时五个数据区域的主要特点
1,程序计数器(Program Counter Register)
作用:当前线程所执行的字节码的行号指示器
特点:
1)每条线程都有一个独立的程序计数器,互不干扰,独立存储,所以我们称它为“”线程私有“的区域。
2)如果线程正在执行一个java方法,程序计数器记录的是正在执行的虚拟机字节码指令的地址,如果正在执行的是native方法,则计数器值为空。
3)程序计数器是唯一一个Java虚拟机中没有规定任何OutOfMemoryError情况的区域。
2,Java虚拟机栈(Java Virtual Machine Stacks)
作用:描述Java方法执行的内存模型。每个方法被执行时都会创建一个栈帧,栈帧中存储着这个方法的局部变量表等等相关信息,每个方法的栈帧都进栈放到Java虚拟机栈,栈帧进栈对应着方法开始执行,栈帧出栈对应方法执行结束。
特点:
1)平时大家把Java内存区分为堆内存(Heap)和栈内存(Stack),这种方法比较粗糙,其实此处的”栈“就是这里的Java虚拟机栈,或者说是虚拟机栈中的局部变量表部分。
2)每个方法的栈帧分配多大的局部变量空间表示在编译期间确定的,在方法运行期间不会改变局部变量表的大小。
3)这个区域有两种异常
3,本地方法栈(Native Method Stacks)a,StackOverflowError异常:线程请求的栈深度大于虚拟机所允许的深度(不可以动态扩展)
b,OutOfMemoryError异常:虚拟机栈可以动态扩展,扩展时无法申请到足够的内存。
作用:本地方法栈和虚拟机栈所发挥的作用相同,但是针对的是native方法。
特点:抛出StackOverflowError异常与OutOfMemoryError异常,抛出的原理和虚拟机栈对应的原理相同。
4,Java堆(Java Heap)
作用:此内存的唯一目的就是存放对象实例与数组。(但是随着一些新的技术的发展,比如JIT编译器,逐渐出现了栈上分配等等方式)
特点:
1)垃圾收集器管理的主要区域就是Java堆,Java堆是被所有线程共享的一块内存区域,此内存区域的唯一目的是存放对象实例。
2)Java堆是垃圾收集器管理的主要区域,也是我们常说的“GC堆”,现在收集器基本都是采用分代收集算法,所以Java堆中还可以细分为:新生代和老年代。
3)Java堆不一定要处于物理上的连续状态。只需要是逻辑上连续即可。
4)Java堆可以设置为固定大小或者可扩展的。当前主流的虚拟机都是设置为可扩展的(通过-Xmx和-Xms控制),所以一般情况下Java堆抛出的异常是:OutOfMemoryError异常
5,方法区(Method Area)
作用:存储已被虚拟机加载的类信息,常量,静态变量等数据
特点:
1)和Java堆类似,方法区在物理上可以不连续,可以选择固定大小或者扩扩展。
2)方法区是Java堆的一个逻辑部分,但是可以不实现垃圾回收,垃圾收集行为在这个区域极少出现。但是还是必须适当地进行垃圾回收,主要是针对其中的常量池。
tips:
StackOverflowError异常:线程请求的栈深度大于所允许的深度(不可以动态扩展)
OutOfMemoryError异常:某个区域可以动态扩展,扩展时无法申请到足够的内存(可扩展)
其他
关于运行时常量池以及直接内存,后续再学习。