今天记录并巩固下学到的JVM相关知识,JVM的内存模型大致能分为5个大块:程序计数器(Program Counter Register),虚拟机栈 (Virtual Machine Stack),本地方法栈(Native Method Stack),堆(Heap),以及方法区(Method Area)。
程序计数器:程序计数器占用一小块内存,用于标识当前线程所执行的字节码的行号,程序运行时,字节码解析器会通过改变程序计数器的值来获取下一条需要执行的字节码指令,通过这个计数器可以实现程序的循环、跳转等功能。Java的多线程在确定的某一时刻只会有一个线程在运行,因此每条线程为了能够保证当轮到该线程执行时知道该从什么地方开始执行,每一条线程都会保有自己的一个独立计数器。注意:当正在执行的方法是native的,该计数器为undefined。并且在Java中程序计数器所在的内存没有规定OOM(OutOfMomery)这种情况。
虚拟机栈:Java中每个方法执行时,都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。一个方法从被调用到执行完成,也是该方法对应栈帧从虚拟机栈入栈出栈的过程。因为栈帧是和方法息息相关,栈帧所在虚拟机栈也是线程私有型即虚拟机栈的生命周期与线程的生命周期相同。如果栈帧的数量大于虚拟机栈的深度,那么虚拟机栈就会报SOE(StackOverflowError,一般来说JVM是允许虚拟机栈进行扩展的,若虚拟机栈无法申请到更多的内存,则会报OOM(OutOfMomeryError)。
本地方法栈:本地方法栈作用于native方法执行时。对于本地方法栈,其使用方式、语言数据结构等等都没有强制规定和虚拟机栈一样根据实际情况也会报StackOverflowError以及OutOfMomeryError。
堆:堆是JVM中占内存最大一个。在Java中,堆是被所有线程共享的,它用于存储对象实例。Java堆也是Java GC(Garbage Collection)主要作用的区域。在实际情况中,堆有可能分出多个线程私有的分配缓冲区TLAB(Thread Local Allocation Buffer),其目的是为了更好地管理内存更高效地回收内存。同样,如果堆无法进行扩展,则会报出OutOfMenoryError.
方法区:也称静态区,它与堆一样也是为各个线程所共享。其主要作用为存储虚拟机已加载的类信息、常量、静态变量、静态方法(这也是为什么静态方法不需要实例化能够直接调用的原因)。