文章目录
jvm虚拟机由三部分组成:
类装载子系统,运行时数据区,执行引擎
类装载子系统
运行时数据区
程序计数器:记录代码执行的位置
当前线程所执行的字节码的行号指示器,用它来进行选取下一条指令,线程专有
栈(线程栈)
作为代码运行期间的动态内存,承担计算等功能,线程专有
虚拟机栈:给java代码服务
用于在代码运行期间存储局部变量表、操作数栈、动态链接、方法出口等信息,其中局部变量表保存基本数据类型(比如int,byte等)、对象引用和returnAddress类型
分析javap反汇编后的代码,以确定“局部变量表、操作数栈”的作用:
举例java代码如下:
public int comp() {
int a = 1;
int b = 2;
int c = (a + b) * 10;
return c;
}
javap -c *.java进行反汇编
public int comp();
Code:
0: iconst_1//将数据1放入操作数栈
1: istore_1//给a在局部变量表申请空间并将操作数栈的1取出赋值给他
2: iconst_2//同上
3: istore_2//同上
4: iload_1//将a的值1加载到操作数栈
5: iload_2//同上
6: iadd//此时操作数栈最下是1,1上是2,将2和1取出相加,并将结果3压入操作数栈
7: bipush 10//压入一子节数据(-127~128)10
9: imul//此时操作数栈最下是3,3上是10,将10和3取出相乘,并将结果30压入操作数栈
10: istore_3//给c在局部变量表申请空间并将操作数栈30的取出赋值给他
11: iload_3//将c的值30加载到操作数栈
12: ireturn//返回操作数栈的值
- 操作数栈
以上代码可以看出操作数栈其实就是一个中间暂存数据的空间,cpu需要从操作数栈中取值进行计算,操作数栈符合FILO(先进后出)原则,操作数栈计算好的数据如果需要赋值给局部变量需要istore到局部变量表
istore 操作数栈->局部变量表 - 局部变量表
以上代码可以看出局部变量表就是一个局部变量存放的空间,相当于将计算结果赋值给局部变量的时候放入的空间,如果程序需要随时可以将数据iload到操作数栈
iload 局部变量表->操作数栈 - 动态链接
动态链接区存储的是方法本身的地址,但动态链接区是动态存储的,也就是说方法调用完后可以销毁此地址,真正方法的指令码存储在方法区(元空间)的类信息中,过程是这样的:
1、一个类加载进方法区(元空间)
2、new这个类的对象,然后通过对象调用这个类的相应方法
3、new出来的这个对象中包含这个类的方法区(元空间)地址(在对象头中存储),此对象通过这个地址找到这个类在方法区(元空间)中的位置,并找到他要执行方法的位置将找到方法的地址加载进动态链接区,所以动态链接区是用来存储方法的指针 - 方法出口
就是一个方法的出口
本地方法栈:给非java代码服务
存储的数据和虚拟机栈一样,只是给native方法使用的,比如调用的C语言方法,线程专有
内存不够时会抛出OutOfMemoryError
堆:存放对象的和数组
堆空间线程共有,堆中存放对象信息和数组信息,还有一些其他数据信息,也就是比较多的数据一般都会放在堆中,但堆中不关是对象还是数组都需要栈或者方法区有指针指向,否则堆中的信息就会变为游离数据,会被jvm回收(minor gc或者full gc的时候),堆空间的分配:
堆空间是可以调整大小的,默认情况下老年代占比80%,Eden(伊甸园区)、suirivor(幸存者区由from和to两个组成,一般from和to的大小一样)共占20%,老年代的比例可以调整,其中Eden:from:to=8:1:1,这里Eden和from、to的比例也是可以调整的(这里suirivor区之所有from和to两个区主要是因为拷贝对象的算法需要)
一个对象的生死例程:
1、new出来一个对象首先进入Eden区
2、Eden区满的时候会出发minor gc将对象放入from区
3、如果Eden再次满再次出发minor gc对象从from区会进入to区
4、再来一次minor gc从to区进入from区,每经历一次minor gc会使对象的年龄增长1(存储在对象头部)
5、这个对象往复循环,默认年龄到15的时候会进入老年代(这个也可以调整)
方法区(元空间,也叫永久代):堆中存放代码和静态变量、常量、类信息、即时编译器编译代码等数据的地方**
存放类信息,存入类的常量、静态变量、方法、类元信息(*.class)
运行时常量池:方法区中存放常量的地方
内存不够时会抛出OutOfMemoryError
直接内存:不受虚拟机控制的内存,比如io的缓冲区
内存不够时会抛出OutOfMemoryError
执行引擎
备注及参考资料
可以通过javap -c *.class进行反汇编操作,可以查看.class文件的指令码,以下是指令码对照表
jvm指令码详解
jvm相关参数查询