这里简单说一下自己对于JVM的理解,如果有不正确的地方欢迎大家指正。
JVM运行时数据区分为程序计数器、虚拟机栈、本地方栈、堆和方法区。其中前三个即程序计数器、虚拟机栈、和本地方发栈是线程私有的。另外两个是所有线程共享的。
程序计数器当中记录的是当前程序执行的字节码的行号指示器,因为要线程之间要进行切换以实现计算机的并发处理,所以每个线程都必须有自己的程序计数器。如果程序正在执行的是NATIVE方法,则计数器的值为空(Undifined)。此内存区域是唯一一个没有OutOfMemoryError的区域。
虚拟机栈的生命周期是和线程相同的。它描述的是方法执行的内存模型,每个方法执行时都会创建一个栈帧,方法从调用到完成的过程就对应着栈帧在虚拟机栈中的入栈和出栈过程。占中用于存储局部变量表,方法出口等信息。局部变量表中存储基本数据类型、对象引用类型和returnAddress类型。虚拟机栈又分为固定长度和可动态扩展。如果请求的栈深度超过虚拟机栈所允许的深度则会抛出StackOverflowError异常,如果动态扩展时无法申请到足够的内存时则会抛出OutOfMemoryError异常。
本地方法栈和虚拟机栈作用类似,只不过是为Native方法服务的。naative方法实质是指用其他语言编写的方法。
堆的唯一目的就是存放对象实例。是垃圾回收的主要区域。从内存分配的角度来看,线程共享的java堆中可能划分出多个线程私有的分配缓冲区(TLAB),堆可以处于物理上不连续的内存。
方法区用于存储被虚拟机加载的类信息,常量,静态变量等。它是堆的而一个逻辑部分,却有一个别名“Non—heap”,这个蛮有意思的。这个地方可以不识闲垃圾回收,如果要回收的话也是针对常量池和对类型的卸载。
运行时常量池是方法区的一部分,它相对与Class文件的常量池具有动态性,不要求常量一定只有在编译时产生,也可以在运行期间将新的常量放入池中,比如String类的intern()方法。