JVM虚拟机原理与调优详解

JVM虚拟机原理与调优详解

文章目录

  • JVM虚拟机原理与调优详解
    • JVM java虚拟机
        • JVM从软件的层面屏蔽了底层硬件指令层面的细节
      • JVM是什么
      • JDK>JRE>JVM
  • JVM底层的原理
          • 执行引擎去执行代码
          • 硬件上来说执行引擎是cpu 软件角度上说是线程
    • JVM运行时数据区
      • 栈帧中的内容
          • 即上述add栈帧与main栈帧都有这些内容
      • 程序计数器 与 行号
      • 本地方法栈
      • 元空间(方法区)
    • 堆(重要)
    • 垃圾回收机制
          • 新生代的minor gc
        • 此种方式 称为 担保机制
        • 老年代的 full gc
        • Java VisualVM 自带的监控整个对象内存分配情况
      • 问题:为什么JAVA需要进行性能调优
          • 在有限的空间做更多的事情
      • 问题:为什么JAVA需要采用分代回收的策略思想
          • 为了让更少的对象进入老年代 减少STW次数的出现

JVM java虚拟机

JVM从软件的层面屏蔽了底层硬件指令层面的细节

JVM虚拟机原理与调优详解_第1张图片

JVM是什么

  1. java源码文件——>.class文件
问题:操作系统底层对应的都是机器码010101

不同的操作系统底层对应的机器码、指令是不同的

JVM来解决这个问题 从软件层面屏蔽了底层硬件指令层面的细节

在下载的时候就将操作系统进行了分类 linux与java
  1. c c++跨平台性
  2. redis
  3. JDK JRE JVM
整个的java知识体系就是JDK

JRE叫做java运行时环境 (jdbc lang util等等)

JVM 分类:

1.Java Hotspot Client VM

2.Java Hotspot Sever Vm

3.Selaris linux Windows other

JDK>JRE>JVM

JVM虚拟机原理与调优详解_第2张图片

JDK与JRE之间的差别 

JDK比JRE多了Tools&Tool APIS

Tools&Tool APIS是java自带的工具 java javac javadoc等等

源码文件到.class文件 是JDK编译时环境

java的跨平台:JVM跨平台 属于JRE运行时环境

c与c++的跨平台是在编译时环境进行的跨平台 分操作系统的类库

JVM底层的原理

  • Java虚拟机底层的构成

JVM虚拟机原理与调优详解_第3张图片

  • 内容
    1. 类加载子系统
    2. 执行引擎
    3. JVM运行时数据区 在计算机内存中
源码文件 生产字节码文件.class 存储在本地计算机硬盘中

java HelloWorld.class 执行字节码文件

类加载子系统将.class加载到JVM运行时数据区

JVM运行时数据区在我们计算机的内存中

执行引擎去执行它 也就是CPU分配时间调度去执行它

即类加载子系统--JVM运行时数据区--执行引擎
执行引擎去执行代码
硬件上来说执行引擎是cpu 软件角度上说是线程

JVM运行时数据区

  • 内容:
    1. 本地方法栈
    2. 方法区(元空间)
    3. 程序计数器
其中 堆与方法区属于线程共享数据

栈 本地方法栈 程序计数器器 属于线程私有数据

处理高并发的项目的时候 并发问题 :就是当用户在同一时间访问同一共享数据区域 得到的结果会与理想结果存在差异 例如:100个线程执行i++ 结果有可能不是100

代码 由main线程执行

main线程里包含了栈 本地方法栈 程序计数器这三块线程私有数据

每个线程有它独立的栈 本地方法栈 程序计数器空间

  • 栈(先进后出)–数据结构–存储内容
  • 栈来存储方法的结果 根据方法来隔离
  • 例如 栈里面存储着main栈帧与add栈帧
public int add(){
int d=100;
return 100;
}
public static void main(String[] args){
Onject o=new Object();
o.add;
}

执行过程:

  1. main栈帧进入栈
  2. add栈帧进入栈
  3. add栈帧在上面 main栈帧在下面
  4. add栈帧结束后出栈
  5. main栈帧结束后出栈
  6. 符合先进后出原则

栈帧中的内容

JVM虚拟机原理与调优详解_第4张图片

  • 栈帧
局部变量表

操作数栈

方法出口

附加信息

...
即上述add栈帧与main栈帧都有这些内容

javap命令可以对字节码文件进行反汇编

JVM虚拟机原理与调优详解_第5张图片

字节码文件运行在JVM虚拟机 虚拟机依赖于操作系统 操作系统底层是机器码 JVM在这个过程中充当了 字节码与机器码之间的转换角色

JVM虚拟机原理与调优详解_第6张图片

JVM虚拟机原理与调优详解_第7张图片

JVM虚拟机原理与调优详解_第8张图片

  • int a=1;
iconst-1 将int数据1 压入操作数栈

istore-1 将局部变量a存入局部变量表 并且 操作数栈中的1赋值给a
即局部变量表存储着a=1;
  • int b=2;
iconst-2 将int数据2 压入操作数栈
istore-2 将局部变量b存入局部变量表 并且 操作数栈中的2赋值给b
即局部变量表存储着b=2;

JVM虚拟机原理与调优详解_第9张图片
JVM虚拟机原理与调优详解_第10张图片

程序计数器 与 行号

  • 程序计数器:指向当前线程所执行的字节码指令的地址行号
  • 前面的数字就是行号
  • 程序计数器修改字节码指令的地址行号 执行引擎通过行号来执行操作

JVM虚拟机原理与调优详解_第11张图片

  • iload-1 从局部变量表的a=1装载int数据1 装载到操作数栈
  • iload-2 从局部变量表的b=2装载int数据2 装载到操作数栈
操作数栈也是栈 先进后出 所以 2在1的上面

JVM虚拟机原理与调优详解_第12张图片

  • iadd 执行int类型的解法 2与1出栈 执行2+1=3 然后 2与1小事 只保留3

JVM虚拟机原理与调优详解_第13张图片

  • bipush 将8位带符号整数压入栈
7为什么直接到9
7其实包含两个指令 
7 bipush8位带符号整数压入栈 
8 8位带符号整数对应100
也就是将100 压入操作数栈

JVM虚拟机原理与调优详解_第14张图片

  • imul 执行int类型的乘法 100*3=300 100 与3消失 300存入操作数栈

    JVM虚拟机原理与调优详解_第15张图片

  • istore-3 将操作数栈中的int类型 存入局部变量表中的变量c

  • iload-3 将局部变量表中的c的值加载进来 将300加载到操作数栈

JVM虚拟机原理与调优详解_第16张图片

  • ireturn 从add方法栈帧中返回int数据 从方法出口将300传递到main栈帧中的局部变量表 即result=300

JVM虚拟机原理与调优详解_第17张图片

  • HelloWorld app=new HelloWorld();
app存储在JVM运行时数据区的堆中 通过main栈帧的局部变量表中的app指向堆中的app

本地方法栈

  • Thread.sleep();
Sleep()被native修饰的方法 java没有实现 调用底层的c与其他实现

元空间(方法区)

  • 堆中存储的类的实例化对象obj 指向方法区的类class

JVM虚拟机原理与调优详解_第18张图片

堆(重要)

垃圾调优
性能调优
  • JVM运行数据区的堆底层划分
  • JVM虚拟机原理与调优详解_第19张图片
假设600m内存 

堆中老年代占比三分之二 400m

堆中新生代占比三分之一 200m

新生代中Eden占比 五分之四 160m

新生代中from占比十分之一 20m

新生代中to占比十分之一 20m

新生代 老年代

Eden 包含from to

98%的对象在新生代的Eden伊甸园区创建

垃圾回收机制

新生代的minor gc
当创建的对象占满了堆内存中新生代的Eden时 会触发java的垃圾回收机制 minor gc

JVM虚拟机原理与调优详解_第20张图片

  • 第一次触发:当触发了minor gc时 会触发gc root 根的可达性判定

对当前创建的所有对象都进行判定

判定方式为:是否被其他地方所调用

  1. 如果此对象没有被调用 gc root会给此对象标记 标记为游离状态 认为是可回收的
  2. 如果此对象有被调用 该对象就是从Eden离开进入from区 并且该对象one会增加一条age=1;
  • 第二次触发:当Eden区的对象又满了的时候 再次触发minor gc 进行gc root 根的可达性判定 判定方式同上

如果two对象被调用 将他传入from区 并增加age=1;

这时 如果之前的one对象还是处于被调用的状态 那么他的age变为2 age=2;

并且 将one与two对象拷贝到to区

to区变为from区 froom区变为to区

  • 第三次触发:

当Eden区的对象又满了的时候 再次触发minor gc 进行gc root 根的可达性判定 判定方式同上

如果three对象被调用 将他传入from区 并增加age=1;

这时 如果之前的one对象还是处于被调用的状态 那么他的age变为3 age=3;

如果two对象不被调用了 two对象被移除

然后 将one与three对象拷贝到to区

to区变为from区 froom区变为to区

当minor gc进行15次之后 即one的age=15的时候

JVM会认为one对象是“老不死的对象”

此时one对象会进行晋升 晋升到老年代

此种方式 称为 担保机制
老年代的 full gc

JVM虚拟机原理与调优详解_第21张图片

  • 晋升
    1. age=15 老年代
    2. 当前创建对象内存占比50% 会晋升老年代
假如from内存为40m 当from区中的对象占比20m时 这20m对象都会晋升 成为老年代

触发full gc会出现 STW现象(停顿现象)

JVM虚拟机原理与调优详解_第22张图片

JVM分配内存在进行压缩的时候 会占用一些资源 导致程序会出现不能响应的问题 即STW

STW Stop-The-World
是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互;这些现象多半是由于gc引起

例如 双十一 不能出现停顿

Java VisualVM 自带的监控整个对象内存分配情况

问题:为什么JAVA需要进行性能调优

JVM虚拟机原理与调优详解_第23张图片

JVM虚拟机原理与调优详解_第24张图片

当我们创建的对象越来越多的时候 堆所使用的内存越来越多 JVM分配的内存也会越来越大

当JVM分配的内存达到临界值的时候 会进行JVM分配内存的压缩 进行性能调优 也就是垃圾回收

进行性能调优的原因 :

在有限的空间做更多的事情

问题:为什么JAVA需要采用分代回收的策略思想

JVM虚拟机原理与调优详解_第25张图片

对象在新生代存活15次 尽量在新生代就被回收

实在不行 再晋升老年代

JAVA采用分代回收思想的原因:

为了让更少的对象进入老年代 减少STW次数的出现

你可能感兴趣的:(Java底层知识,jvm,java,栈,jdk,操作系统)