本编博文介绍的主要内容
- JVM内存布局概述
- 对PC寄存器的细究
- 虚拟机栈
1.JVM内存布局概述
- 总的来说JVM内存区分为堆区,方法区,程序计数器,本地方法栈,虚拟机栈。其中方法区和堆区是由整个程序共享的,即图中的红色部分。灰色部分对每一个线程来说是私有的。
- 注意这里的程序计数器是软件意义上的,区别于计算机的PC。用来指向每一个线程下一条指令的地址。
- 本地方法接口或者本地库指的是java当中用native修饰的方法,这一类方法通过调用C语言或者C++的函数辅助完成自己的功能。
下面附上一张阿里对JMV内存布局的划分,总的来说,与上图大同小异:
2.对PC寄存器的细究
执行引擎通过追踪PC寄存器所指向的指令位置,来解析当前的指令。再填充相应的局部变量表,操作数栈。
那么我们为什么需要使用程序计数器呢?
答:因为CPU需要不停的切换执行各个线程,从另一一个切换回来继续执行本线程的时候,需要知道上一次指定到哪一个位置。JVM的字节码解释器的值来明确下一条应该执行什么样的字节码指令。
为什么要把程序计数器设置为线程私有呢?
答:CPU切换的执行线程的某个方法,这样必然导致经常的终端和恢复,为了能够准确的记录各个线程正在执行的字节码的地址,设置为私有最为合理。防止了线程间轮流在CPU上执行时对彼此的干扰。
3.虚拟机栈
-
虚拟机栈的主要特点
每一个线程只有一个虚拟机栈,每一个方法组成一个栈帧。
-
虚拟机栈的常见异常与如何设置栈的大小
虚拟机栈常见的异常有两种:如果栈的大小事先是固定的,那么当我们的操作太过复杂时会出现栈溢出,即StackOverFlow的异常。
下面的程序递归的调用main方法,没有指定递归的出口,会一直调用下去,直至栈溢出.
public class Runtime2 {
public static void main(String[] args) {
main(args);
}
}
Exception in thread "main" java.lang.StackOverflowError
at com.psf.runtime.Runtime2.main(Runtime2.java:5)
at com.psf.runtime.Runtime2.main(Runtime2.java:5)
at com.psf.runtime.Runtime2.main(Runtime2.java:5)
at com.psf.runtime.Runtime2.main(Runtime2.java:5)
如何指定栈的大小呢?
通过设定-Xss@,@表示需要设置的空间大小:
设置完参数后继续测试:
没有规范栈大小递归执行的次数: