JDK体系及JVM架构详解

JDK,JRE,JVM等基础概念

  • 我们通常所说的JDK,其实是指Java开发包,里面包含Java开发用到的工具集。

JDK(Java DevelopmentToolKit)

  • 包含了Java运行环境(JRE)和开发工具(编译器,调试器,javadoc等)。我们就是依靠JDK来开发和运行Java程序的。
  • JDK的编译器Javac[.exe],会将Java代码编译成字节码(.class文件)。编译出的字节码在任何平台上都一样的内容,所以我们说Java语言是门跨平台语言。Writeonce, run anywhere。

JRE(Java Runtime Environment)

  • 它为Java提供了运行环境,其中重要的一环就是通过JVM将字节码解释成可执行的机器码。
    JRE由JVM,Java运行时类库,动态链接库等组成。

  • JVM(Java Virtual Machine),Java虚拟机,可以看做是一台抽象化的计算机,它有一套完整的体系架构,包括处理器、堆栈、寄存器等。

  • 在运行时环境,JVM会将Java字节码解释成机器码。机器码和平台相关的(不同硬件环境、不同操作系统,产生的机器码不同),所以JVM在不同平台有不同的实现。目前JDK默认使用的实现是Hotspot VM。

JDK体系及JVM架构详解_第1张图片

JDK体系及JVM架构详解_第2张图片JDK体系及JVM架构详解_第3张图片
JDK体系及JVM架构详解_第4张图片

栈 (线程)

  • 每当启动一个新线程的时候,java虚拟机都会为它分配一个java栈。
    java栈主要用来存储局部变量,如下图当执行main方法时,就启动了一个线程,
    java虚拟机都会为它分配一个栈内存区域用来存储局部变量a,b,c

JDK体系及JVM架构详解_第5张图片

栈帧

  • java以栈帧为单位保存线程的运行状态。虚拟机只会对java栈执行两种操作:
    以栈帧为单位的压栈或者出栈。一个方法对应一块栈帧内存区域,栈帧遵循栈的
    先进后出原则FILO

JDK体系及JVM架构详解_第6张图片

  • 栈帧主要由以下几部分组成
  1. 局部变量表
  2. 操作数栈
  3. 动态链接
  4. 方法出口

JDK体系及JVM架构详解_第7张图片

局部变量表和操作数栈详解

  • 局部变量表:存放局部变量,如a=1,b=2
  • 操作数栈:临时存放操作数

javap-c命令 可以对代码进行反汇编,生成可读JVM字节指令码
在这里插入图片描述
JDK体系及JVM架构详解_第8张图片
以上compute方法对应的JVM指令码如下
JDK体系及JVM架构详解_第9张图片
查询JVM指令手册可知
iconst_1 将int类型常量1压入栈
istore_1 将int类型值存入局部变量1
在局部变量表给a分配内存区域,将操作数栈1的值赋给a
JDK体系及JVM架构详解_第10张图片
JDK体系及JVM架构详解_第11张图片
iconst_2 将int类型常量2压入栈
istore_2 将int类型值存入局部变量2
在局部变量表给b分配内存区域,将操作数栈2的值赋给b

JDK体系及JVM架构详解_第12张图片
JDK体系及JVM架构详解_第13张图片
iload_1 从局部变量1中装载int类型值
iload_2 从局部变量2中装载int类型值

JDK体系及JVM架构详解_第14张图片
iadd 执行int类型的加法
从操作数栈顶弹出1和2,相加,并将结果3重新压回操作数栈
JDK体系及JVM架构详解_第15张图片
JDK体系及JVM架构详解_第16张图片
bipush 将一个8位带符号整数压入栈
bipush 10 将10压入操作数栈
JDK体系及JVM架构详解_第17张图片
imul 执行int类型的乘法
从操作数栈顶弹出10和3,相乘,并将结果30重新压回操作数栈
JDK体系及JVM架构详解_第18张图片
istore_3 将int类型值存入局部变量3
在局部变量表给c分配内存区域,将操作数栈30赋给c
JDK体系及JVM架构详解_第19张图片
iload_3 从局部变量3中装载int类型值
ireturn 从方法中返回int类型的数据
返回局部变量c的值

JDK体系及JVM架构详解_第20张图片

堆和栈的关系

  • 栈存的是new在堆中对象的指针
  • main()方法栈帧,math局部变量是new出来的,new出来的对象是存放在堆内存中,
    栈中math变量记录的是堆内存math对象的地址

JDK体系及JVM架构详解_第21张图片

方法区详解

  1. 方法区主要用来存放常量静态变量类信息math.class
  2. 对象的静态变量也是在堆中new出来,方法区存放的是对堆对象的引用/指针

以下两个变量就是放在方法区中
在这里插入图片描述
JDK体系及JVM架构详解_第22张图片JDK体系及JVM架构详解_第23张图片

本地方法栈详解

  1. 本地方法:有native修饰,由C语言实现,java跨语言调用C
  2. 本地方法栈是本地方法运行时所需要的内存区域

在这里插入图片描述
JDK体系及JVM架构详解_第24张图片

堆内存详解

  1. new出来的对象放到Eden中
  2. Eden内存大小有限制,当new的对象过多放满时,java会调用字节码执行引擎 开启后台线程执行垃圾收集minor gc,处理垃圾对象
    JDK体系及JVM架构详解_第25张图片
  3. 垃圾对象如何查找,通过GC root根查找垃圾对象

JDK体系及JVM架构详解_第26张图片

  • 非垃圾对象:如图GC Root对象(math,user),从栈中的math查找发现
    栈中的math是堆中的math的引用,然后在看看堆中math是否引用其它对象,直到对象没有引用其它对象,依次查找形成的琏条上的对象就是非垃圾对象,不能被回收,其它不在链条上的堆对象为垃圾对象

  • 垃圾对象:假设main方法执行完,线程执行完了,Java虚拟机还没有结束,
    栈中的局部变量math不存在了,指针消失,math对象还存在堆里,
    此时堆中的math对象就是垃圾对象

JDK体系及JVM架构详解_第27张图片
4.将Eden中查找到的非垃圾对象复制到Suvivor存活区中的from,
剩余的垃圾对象一次性清理掉
JDK体系及JVM架构详解_第28张图片
当经历过一次minor gc后,复制到Suvivor存活区中的变量的分代年龄加一
JDK体系及JVM架构详解_第29张图片
随着程序的运行,更多的对象被创建,Eden会被放满,
下一次minor gc除了Eden会被回收,Survior的From区也会被回收
JDK体系及JVM架构详解_第30张图片
当Eden放满,Eden的存活对象和From区的存活对象会被复制到Survior的To区,
并且分代年龄加1
JDK体系及JVM架构详解_第31张图片
当Eden再一次放满,Eden的存活对象和To区的存活对象会被复制到Survior的From区,
并且分代年龄加1
JDK体系及JVM架构详解_第32张图片
随着Eden多次放满和多次GC后,来回流转,当对象的分代年龄达到15时还没被清理掉会被移到老年代,如静态变量,缓存,线程池,spring bean容器

JDK体系及JVM架构详解_第33张图片
随着程序的运行,老年代也会被放满,如下例子
JDK体系及JVM架构详解_第34张图片
老年代被放满会导致内存溢出
在这里插入图片描述
老年代被放满会先做一个full gc,尝试收集整个堆的内存,
如果没有什么垃圾对象可被回收,这时就会导致内存溢出OOM
JDK体系及JVM架构详解_第35张图片
容易触发堆内存溢出的代码

JDK体系及JVM架构详解_第36张图片
java虚拟机调优目的:减少STW (Stop The Work),减少full gc的次数和缩短full gc的时间

你可能感兴趣的:(JVM,java,jvm)