jvm学习笔记

文章目录

    • jvm虚拟机由三部分组成:
      • 类装载子系统
      • 运行时数据区
        • 程序计数器:记录代码执行的位置
        • 栈(线程栈)
          • 虚拟机栈:给java代码服务
          • 本地方法栈:给非java代码服务
        • 堆:存放对象的和数组
        • 方法区(元空间,也叫永久代):堆中存放代码和静态变量、常量、类信息、即时编译器编译代码等数据的地方**
        • 运行时常量池:方法区中存放常量的地方
        • 直接内存:不受虚拟机控制的内存,比如io的缓冲区
      • 执行引擎
      • 备注及参考资料

jvm虚拟机由三部分组成:

类装载子系统,运行时数据区,执行引擎jvm学习笔记_第1张图片

类装载子系统

运行时数据区

程序计数器:记录代码执行的位置

当前线程所执行的字节码的行号指示器,用它来进行选取下一条指令,线程专有

栈(线程栈)

作为代码运行期间的动态内存,承担计算等功能,线程专有

虚拟机栈:给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的时候),堆空间的分配:
jvm学习笔记_第2张图片
堆空间是可以调整大小的,默认情况下老年代占比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相关参数查询

你可能感兴趣的:(java虚拟机)