JVM性能调优和底层原理分析

JVM虚拟机

JVM性能调优和底层原理分析_第1张图片

JVM虚拟机的组成:

类装载子系统,字节码执行引擎,以及运行时数据区(内存模型)
运行时数据区又分为堆、栈(线程)、本地方法栈、方法区(元空间)、程序计数器

JVM是如何运行的?

程序在加载字节码文件时,会首先在栈中分配一块内存区域,运行main方法时,又会在该内存区域中分配一个栈帧,依次调用方法时,依次分配栈帧,方法执行完,栈帧销毁,先加载的后执行,后加载的先执行先销毁。
JVM性能调优和底层原理分析_第2张图片

栈帧

栈帧内部组成部分

局部变量表

是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量

操作数栈

存放临时的操作数的内存区域

动态链接

Class 文件中存放了大量的符号引用,字节码中的方法调用指令就是以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或第一次使用时转化为直接引用,这种转化称为静态解析。另一部分将在每一次运行期间转化为直接引用,这部分称为动态链接

方法出口

方法出口是一个内存区域,记录的是该方法调用完成后返回上层方法的哪一行代码

程序计数器

程序计数器是每个栈独有的,记录当前运行的字节码的行号。
当多线程的时候,当前线程挂起,执行其他的线程,最后要继续执行当前线程时就需要程序计数器来记录当前线程执行到哪一行字节码,然后继续往下执行

方法区

方法区(元空间)存放的是产量,静态变量,类信息(类信息就是类装载子系统装载字节码文件时就会先经过一系列解析放在方法区中通俗来说类信息就是装载的那个字节码文件)

本地方法栈

本地方法是java底层用native修饰的方法,是为了兼容java没面世之前,大部分公司都使用的c语言,汇编语言的程序与java之间的交互。当需要执行本地方法时,会去操作系统(比如是windows系统)本地的库函数找到xx.dll文件(相当于java里面的jar包),里面有许多c语言的函数的实现。
本地方法栈实际上就是本地方法在运行时需要的一块内存空间
每一个线程在调用本地方法时都有一个本地方法栈

new出来的对象是放在堆中的
示例
如果方法中有一个局部变量是对象类型:
Math math=new math();
栈中的局部变量表中实际放的是堆中的math对象的一个引用(地址值)

JVM性能调优和底层原理分析_第3张图片
new 出来的对象一开始在Eden(伊甸园)区中,JVM启动时给堆分配了内存大小,如果不停的new新对象,当Eden区满了以后会触发字节码执行引擎开启的垃圾回收线程(minor gc),采用的是可达性分析算法:将“GC ROOTS对象”作为起点,从这些节点开始向下搜索引用的对象,找到的对象都标记为非垃圾对象,其余未找到的对象都是垃圾对象
(GC ROOTS根节点:线程栈的本地变量,静态变量,本地方法栈的变量等)

垃圾回收:

JVM性能调优和底层原理分析_第4张图片
GC找到Eden区中的所有非垃圾对象,采用复制算法将Eden区中的所有非垃圾对象复制到Survivor区中的From区。然后一次性清空Eden区,然后下一次Eden区放满以后,GC会去Eden区和From区中找到非垃圾对象,放到To区,一次性清空Eden区和From区,再下一次,GC又会去找到To区和Eden区中的所有非垃圾对象,放到From区,清理To区和Eden区,循环往复

当一个对象经历一次minor gc还没有被清理掉,该对象的分代年龄(对象有一个区域是对象头,对象头里面有一个GC分代年龄,一开始是0)会加一,当一个对象的分代年龄到15(可以设置,默认是15)还没被清理掉,就会被放到老年代区中,当老年代都放满了以后,不会立刻OOM(内存溢出),而是会做一次Full GC,它会去尝试收集整个堆的内存,如果还没收集到垃圾对象,就会OOM

注意:JVM调优的目的就是为了减少STW(Stop-The-World:在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互;这些现象多半是由于GC引起),STW会让用户等待,由于Full GC会去收集整个堆的内存,因此耗时会很长,用户等待时间也会很长,为了避免用户糟糕的体验就需要进行JVM调优

对象动态年龄判断:

当前放对象的Survivor区里面(其中一块区域,放对对象的区域)一批对象的总大小大于这块Survivor区域大小的50%,那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代,对象动态年龄判断机制一般是在minor gc之后触发的

面试题
是否可以对JVM调优,让其几乎不发生Full GC
JVM性能调优和底层原理分析_第5张图片
可以将Survivor区的大小设置大一点,避免对象动态年龄判断将对象直接移入老年代

你可能感兴趣的:(JVM性能调优和底层原理分析)