程序计数器
程序计数器(Program Counter Register)是JVM中一块较小的内存区域,保存着当前线程执行的虚拟机字节码指令的内存地址。Java多线程的实现,其实是通过线程间的轮流切换并分配处理器执行时间的方式来实现的,在任何时刻,处理器都只会执行一个线程中的指令。在多线程场景下,为了保证线程切换回来后,还能恢复到原先状态,找到原先执行的指令,所以每个线程都会设立一个程序计数器,并且各个线程之间不会互相影响,程序计数器为"线程私有"的内存区域。
如果当前线程正在执行Java方法,则程序计数器保存的是虚拟机字节码的内存地址,如果正在执行的是Native方法(非Java方法,JVM底层有许多非Java编写的函数实现),计数器则为空。程序计数器是唯一一个在Java规范中没有规定任何OutOfMemory场景的区域。
虚拟机栈
虚拟机栈(Java Virtual Machine Stacks)和线程是紧密联系的,每创建一个线程时就会对应创建一个Java栈,所以Java栈也是"线程私有"的内存区域,这个栈中又会对应包含多个栈帧,每调用一个方法时就会往栈中创建并压入一个栈帧,栈帧是用来存储方法数据和部分过程结果的数据结构,每一个方法从调用到最终返回结果的过程,就对应一个栈帧从入栈到出栈的过程。
虚拟机栈是一个后入先出的数据结构,线程运行过程中,只有一个栈帧是处于活跃状态的,被称为"当前活动帧栈",当前活动帧栈始终是虚拟机栈的栈顶元素。
本地方法栈
本地方法栈(Native Method Stack)和虚拟机栈的作用相似,不过虚拟机栈是为Java方法服务的,而本地方法栈是为Native方法服务的。
方法区
方法区(Method Area)是用于存储类结构信息的地方,包括常量池、静态变量、构造函数等类型信息,类型信息是由类加载器在类加载时从类文件中提取出来的。
方法区同样存在垃圾收集,因为用户通过自定义加载器加载的一些类同样会成为垃圾,JVM会回收一个未被引用类所占的空间,以使方法区的空间达到最小。
方法区中还存在着常量池,常量池包含着一些常量和符号引用(加载类的连接阶段中的解析过程会将符号引用转换为直接引用)。
方法区是线程共享的。
堆
堆(heap)是存储java实例或者对象的地方,是GC的主要区域,同样是线程共享的内存区域。