首页 > 编程知识 正文

java jvm原理,jvm是什么意思

时间:2023-05-06 12:42:37 阅读:50596 作者:468

JVM配置/JVM垃圾回收的原理机制/JVM调整方案基础JVM内存模型Java虚拟机结构图JVM构成虚拟机堆栈:堆栈帧堆栈帧堆栈内的执行过程:程序计数器为什么要设计程序计数器:程序计数器的执行塔克JVM垃圾回收机制可达性分析算法GC过程内存溢出JVM调谐为什么设计STW机(减少全GC发生次数的解决方案(用于独立大内存超高并发系统的JVM调谐(alvm最新JVM调谐工具(Arthas ) (阿尔萨斯) ) ) ) ) ) ) 652

JVM内存模型

JDK体系结构图

Java程序执行流程

使用javac命令编译为**.class**的字节码文件

然后用JVM转换为二进制机器代码

Javavirtualmachineframework在javac中转换为字节码文件,然后在类加载子系统中加载到字节码文件中,并在http://www.com中

由JVM组成的Java虚拟机由三大部分组成:类加载子系统、内存区域(也称为运行时数据区)和字节码执行引擎

JVM内存区域包括堆、虚拟机堆栈(线程堆栈)、本地方法堆栈、方法区域和程序计数器

3358www.Sina.com/:虚拟机堆栈(线程堆栈)、本地方法堆栈、程序计数器内存区域)堆、方法区域、

虚拟机堆栈:用于部署字节码执行引擎。 当线程开始运行时,Java希望为此线程分配专用的内存空间,并从整个虚拟机堆栈中将小块剪切给此线程使用。

如果线程包含线程私有,则当运行到该方法时,将为此方法从线程共享拆分局部变量

堆栈图像:堆栈具有先进的落后特点,首先运行main方法,为mian方法划分空间,然后运行compute方法,为其分配空间。 释放空间时,首先释放compute的空间,然后释放mian方法的空间。

配置堆栈框架配置堆栈框架:局部变量、操作数堆栈、动态链接和方法出口

3358www.Sina.com/:存储方法的本地变量。 注意:例如,如果在main方法中定义了对象,则该对象存储在方法中,但是该对象也是本地变量并且存储在堆栈帧中。 存储在堆栈帧中的是此对象存储在堆中的线程的虚拟机栈:相当于一个零时存储区,JVM在操作数堆栈中是本地变量的加减乘除方法的专属空间(栈帧)请将此方法的字节码放在JVM的局部变量上。请告诉我此他的字节码在方法区域的哪个位置。

字节码文件是二进制格式

javap -c命令可以反汇编内存地址文件,使其成为更可读的格式,从而获得程序更准确的执行过程

下图:可以获取堆栈框架中的运行进程

帧栈中的执行过程:例如

int a=1; int b=2; int c=a b; int a=1;

首先为操作数堆栈分配常量1,然后在操作数栈中为a分配空格,然后在动态链接中堆栈1,并将其放置在a所在的本地变量空间中。

int b=2; 同样的事情。

int c=a b;

将局部变量a的值放在方法区中,将局部变量b的值也放在方法栈帧中,并在操作数堆栈中放在class字节码的顶部

程序计数器为什么要设计程序计数器? Java是多线程执行,如果优先级突然高的线程占用了当前线程的时间片,当前线程将暂时挂起。 程序计数器用于记录当前线程正在运行到哪个步骤。

JVM向程序计数器分配每个线程的专用空间,就像虚拟机堆栈一样

程序计数器的执行进程:当程序运行到该方法时,将此方法的字节码放入JVM的局部变量中,然后返回3358www.Sina.com/执行方法区域中的方法

码执行引擎会修改该线程的程序计数器中的数据。

方法区

在JDK1.8之前叫做永久代/持久代 , 在JDK1.8之后改成叫元空间。

方法区中存放:

方法区中存放:常量、静态变量、类信息
如果这个静态变量是对象, 对象是要放在堆中的,所以方法区中放的就是这个对象在堆中的内存地址。

本地方法栈

JAVA中有两种方法:JAVA方法和本地方法
JAVA方法是由JAVA编写的,编译成字节码,存储在class文件中
本地方法是由其它语言编写的,编译成和处理器相关的机器代码
本地方法保存在动态链接库中,即.dll(windows系统)文件中,格式是各个平台专有的
JAVA方法是与平台无关的,但是本地方法不是。

本地方法:被native修饰的方法。是java用来调用非Java代码(C/C++)的接口。

线程在执行过程遇到本地方法也需要分配空间,这个空间是从本地方法栈中分配

堆由年轻代和老年代组成,年轻代占1/3,老年代占2/3。
年轻代中又分为:Eden区和Survivor区,Survivor区有两块, 比例是8:1:1。
new出来的对象优先放在Eden区,当Eden区满了,JVM会让字节码执行引擎在后台开启一个(minor GC)不安的蚂蚁代垃圾收集线程,用来收集内存区域的垃圾对象。

JVM垃圾收集机制 可达性分析算法

GC Roots根节点:虚拟机栈的局部变量、方法区中的静态变量、本地方法栈的变量等等

将“GC Roots”对象作为起点,从这些节点开始向下搜索引用的对象,找到的对象都标记为非垃圾对象,其余未标记的对象都是垃圾对象。
被标记的非垃圾对象会被复制到Survivor区中 , 剩下的没有被标记的都会被删除回收

GC过程

new出来的对象优先放在Eden区,当Eden区满了,JVM会让字节码执行引擎在后台开启一个(minor GC)不安的蚂蚁代垃圾收集线程, 使用可达性分析算法,标记Eden区中的非垃圾对象,然后将非垃圾对象复制到一块Survivor的s0区中,然后删除Eden区中的数据。

如果Eden区又满了,那么就会再启用minor GC 使用可达性分析算法标记出Eden区与Survivor的s0区中的非垃圾对象,然后将被标记的非垃圾对象,复制到另外一块没有数据的Survivor的s1区中,然后删除原来的Eden区与Survivor的s0区的数据。

如果Eden区又满了,那么会再次标记非垃圾对象,然后再次移动到另外一块Survivor区。就这样在两个Survivor区中来回移动。

分代年龄:标记对象经过几次GC回收,放在对象头中
在Survivor区每一次移动这个对象的分代年龄就会加一,当一个对象的分代年龄达到15的时候,也就是经过15次GC,那么这个对象就会被复制到老年代中。

一个对象中存放的信息
对象有对象头,对象头中存放锁的状态,锁的标记,分代年龄

内存溢出

随着老年代数据的增加,老年代也会被放满。当老年代放满的时候,字节码执行引擎会启动full GC线程。会对整个堆做垃圾收集。如果没有回收到垃圾对象,那么老年代还是满的,同时Survivor区还在往老年代放数据,就会产生内存溢出报错。

JVM调优 JVM调优的目的

减少GC,特别是减少full GC。因为Java有STW机制在执行GC的时候会停掉用户线程,影响用户体验。

为什么要设计STW机制:

在进行标记的时候,如果工作线程不停止的话,那么肯定会有新对象生成。这些对象是没有被标记的,里面可能有存活的对象,也可能有已经没有被引用的垃圾对象。那么我们就需要不停的进行标记,影响我们GC的执行。

案例:
比如有一个电商网站,在活动的时候每秒的订单量特别大,每一个订单都有一个订单对象,一个订单对象有1kb ,这个订单对象可能还关联着优惠券、活动之类的信息。那么这个订单对象就有20kb,那么每秒假设300单,就有600kb/秒,在街上其他的操作,那么每秒大概产生60MB的对象,1秒后就会变成垃圾对象。

运行14秒就会沾满Eden区域,触发minor GC,最后几秒的对象一般不是垃圾对象,会放入Survivor区中,但是Survivor区不一定能放下就会放到Old区域中。Old要不了多久也会马上满了,所以可能几分钟就会触发一次full GC。但是这个时候之前的非垃圾对象已经变成垃圾对象被清除掉了。就不会触发内存溢出,但是频繁的GC会影响用户体验。

让其减少发生Full GC 的次数的解决方案:

调整堆内存空间,之前堆总共3G,年轻代1G,老年代2G,但是老年代不常用,所以从新分配堆内存空间,给年轻代2G,老年代1G,这样Eden区域就有1.6G,Survivor区域分别有200M,

那么之前14秒就会触发minor GC,现在可能要25秒才会触发,那么上一次minor GC 的非垃圾对象很多就会变成垃圾对象被清除了。这样就很少触发Full GC ,只用minor GC就可以解决很多

像这种调整年轻代与老年代的方案适合类似订单这种(对象生命周期特别短)的情况

单机大内存超高并发的系统进行JVM调优

只进行分配空间是不够的,需要针对minor GC与Full GC分别进行调优。
单机大内存的系统,一般年轻代和老年代空间都特别大。
比如,如果Eden区域比较大,等待Eden区域放满了再进行垃圾回收,那么用户线程就会暂停好久,影响用户体验,同时订单的请求可能就会超时。

解决方案:
采用G1垃圾收集器的思想:不等Eden区域全部用完再回收,比如用了三分之一,就开始触发minor GC线程。但是minor GC不会回收整个Eden区域,只回收一部分,因为大内存的Eden区域太大了,全部回收时间太长了。比如只回收十分之一的区域,那么花费时间就特别短,用户线程停顿时间就特别短,基本不会影响用户体验,订单请求就基本不会超时。

G1垃圾收集器有一个设置STW停顿时间的参数

JVM调优工具: jvisualvm

JVM自带一个调优工具:jvisualvm

在命令行中执行jvisualvm这个命令就会打开一个可视化工具,里面有所有的本地的Java正在运行的Java进程

在这里有一个Visual GC,可以查看JVM各个区域的变化
如图:Old区域,Eden区域,S0 区域,s1区域
看图中右侧,s0与s1交替有值

最新JVM调优工具:Arthas(阿尔萨斯)

Arthas是Alibaba开源的Java诊断工具,用来辅助查找JVM的问题。

感谢图灵学院诸葛老师
附老师教学视频:https://www.bilibili.com/video/BV1Eb4y1R7zd?p=2

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。