最近开始看一些JVM的内容,做点笔记和一些代码加深记忆,也方便以后来回顾
JVM运行时数据区
程序计数器:行号指示器,分支,循环,跳转,异常处理,县城回复基础功能依靠计数器记录相应行号。每条县城都需要一个独立的程序计数器,独立存储,线程私有内存,此内存区域是唯一一个在java虚拟机规范中没有任何规定OutOfMemoryError情况的区域
Java虚拟机栈:线程私有,生命周期与线程相同,描述的是Java方法执行的内存模型,每个方法执行时都会创建一个栈帧用于存储局部变量变,操作数栈,动态链接,方法出口等信息,方法从调用到执行完成的过程对应着栈帧在虚拟机栈入栈到出栈的过程。
局部变量表存放基本类型(boolean,byte,char,short,int,float,long,double),对象引用(reference类型)和returnAddress类型(指向一条字节码指令的地址),局部变量变所需内存空间编译期完成分配
虚拟机栈在Java虚拟机规范中规定两种异常①线程请求栈深度大于虚拟机所允许深度,StackOverFlowError异常,对于可动态扩展虚拟机栈当扩展时无法申请到足够的内存抛出OutOfMemoryError
tip:这里边的两个异常栈深度在我理解看来应该是一次方法所请求的内存大小,后面的OOM异常相对比于此处的SOF异常可以算是多次方法请求内存不足的异常,上两段代码说说应该就比较清楚了
public class HeapSOF{
private int count = 0;
public void testAdd(){
count ++;
testAdd();
}
public void test(){
try{
testAdd();
}catch(Throwable e){
System.out.println(e);
System.out.println("栈深度:"+count);
}
}
public static void main(String [] args){
new HeapOOM().test();
}
}
这里的testAdd方法在自己方法体内执行本方法,所以栈深度是无限下沉,本机上执行结果如下
java.lang.StackOverflowError
栈深度:29971
其中每次执行栈深度都会不一样,把代码改动一下,改成OOM异常
public class HeapOOM{
static class OOMObject{
}
public static void main(String[]args){
List<OOMObject>list=new ArrayList<OOMObject>();
int i = 0;
while(true){
list.add(new OOMObject());
list.add(new OOMObject());
System.out.println(i);
i++;
}
}
}
本机执行数次短时间内结果一致,但是间隔三个小时以上在执行结果又会跟三小时之前不一致,但是短时间内仍旧一致,具体什么原因还没搞清楚。所以目前来讲就我认为的栈深度的报异常和内存不足报异常的区别类似于递归和循环的区别。似懂非懂,但却说不明白,等再往后看了看看能不能有更深入的理解
ps:笔记内容大多来自周志明所著《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》