程序计数器:Program Counter Register(PC寄存器),是一块较小的内存,它主要是保存正在执行的字节码的指令地址(行号指示器)。字节码解析器就是通过改变这个程序计数器来选取下一条字节码指令,例如分支,循环,异常,线程恢复后等。由于jvm的多线程是通过轮流切换并分配处理器执行时间来实现的,当被中断的线程当前执行到哪里这个信息是要保存下来的,一遍恢复的时候可以继续执行下去,所以每个线程都会有一个独立的程序技术器,因此它是线程私有的。若线程执行的是native方法,则保存的这个地址为Undefined,不会发生OOM
虚拟机栈:虚拟机栈中存储的就是java中方法的调用状态。每运行一个方法,就会去创建一个栈帧,这个栈帧包括局部变量表,操作数栈,动态链接,方法出口等信息。当一个方法被调用的时候,虚拟机就会压入栈内,当方法调用完成之后就会出栈,在栈顶的栈帧就是正在执行的活动栈,寄存器也会指向该地址。
局部变量表包括:参数,方法里面的定义的基本类型(int、shot、long、byte、char、boolean、float、double),this
public int add(int a, int b) {
int c = 0;
c = a + b;
return c;
}
这个例子中局部变量表有a,b,c,而操作数栈指的是c = a + b这个操作,局部变量表为操作数栈提供数据支撑。
- 因为每调用一个方法就会把一个栈帧压入栈内,当如果栈容量超过虚拟机所允许的最大的容量,就会抛出StackOverflowError,典型的例子就是递归
- 虚拟机栈可以动态拓展,但是如果在拓展的时候无法申请到足够的内存,就会抛出OutOfMemoryException
本地方法栈:与虚拟机栈基本一致,不过它对应的是native方法
java堆:这是一块被线程共享的内存区域,它是用来存放对象实例,几乎所有的对象实例都是在这里进行分配的,在JVM启动的时候创建。Java堆是GC主要管理的区域,它包括新生代和老年代,而新生代又可以分为Eden区,From Survivor和To Survivor
方法区:被线程共享的运行时区域,用来存储已经被Java虚拟机记载的类结构信息(名称,修饰符),包括运行时常量池、Field信息和方法信息,静态变量等数据
常量池:它是属于方法区的一部分,包括字符串,final变量,还有引用量:类名,方法名,权限名,字段名