JVMJava虚拟机

JVM的内存区域

ea5d08f5e6bd059f5c9fb3305dac5fc.png
程序计数器:
字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。
⚠️ 注意:程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。
虚拟机栈:
它的生命周期和线程相同,随着线程的创建而创建,随着线程的死亡而死亡。栈是 JVM 运行时数据区域的核心,除了一些 Native 方法调用是通过本地方法栈实现的,其他所有的 Java 方法调用都是通过栈来实现的。方法调用的数据需要通过栈进行传递,每一次方法调用都会有一个对应的栈帧被压入栈中,每一个方法调用结束后,都会有一个栈帧被弹出。栈由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法返回地址。和数据结构上的栈类似,都是先进后出的数据结构,只支持出栈和入栈两种操作。
与程序计数器一样,Java 虚拟机栈(后文简称栈)也是线程私有的,它的生命周期和线程相同,随着线程的创建而创建,随着线程的死亡而死亡。栈绝对算的上是 JVM 运行时数据区域的一个核心,除了一些 Native 方法调用是通过本地方法栈实现的(后面会提到),其他所有的 Java 方法调用都是通过栈来实现的(也需要和其他运行时数据区域比如程序计数器配合)。方法调用的数据需要通过栈进行传递,每一次方法调用都会有一个对应的栈帧被压入栈中,每一个方法调用结束后,都会有一个栈帧被弹出。栈由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法返回地址。和数据结构上的栈类似,两者都是先进后出的数据结构,只支持出栈和入栈两种操作。

局部变量表
局部变量表是一组变量值的存储空间,用于存储方法参数和局部变量。
局部变量表在编译期间分配内存空间,可以存放编译期的各种变量类型:
基本数据类型 :boolean, byte, char, short, int, float, long, double等8种;
对象引用类型 :reference,指向对象起始地址的引用指针;
返回地址类型 :returnAddress,返回地址的类型。

操作数栈:
主要作为方法调用的中转站使用,用于存放方法执行过程中产生的中间计算结果。另外,计算过程中产生的临时变量也会放在操作数栈中。

动态链接:主要服务一个方法需要调用其他方法的场景。Class 文件的常量池里保存有大量的符号引用比如方法引用的符号引用。当一个方法要调用其他方法,需要将常量池中指向方法的符号引用转化成在内存地址中的直接引用。动态链接的作用就是为了将符号引用转换为调用方法的直接引用,这个过程也被称为 动态连接 。

栈空间不是无限的,但正常调用的情况下是不会出现问题的。不过,如果函数调用陷入无限循环的话,就会导致栈中被压入太多栈帧而占用太多空间,导致栈空间过深。那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。Java 方法有两种返回方式,一种是 return 语句正常返回,一种是抛出异常。不管哪种返回方式,都会导致栈帧被弹出。也就是说, 栈帧随着方法调用而创建,随着方法结束而销毁。无论方法正常完成还是异常完成都算作方法结束。除了 StackOverFlowError 错误之外,栈还可能会出现OutOfMemoryError错误,这是因为如果栈的内存大小可以动态扩展, 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

简单总结一下程序运行中栈可能会出现两种错误:
StackOverFlowError: 若栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。

OutOfMemoryError: 如果栈的内存大小可以动态扩展, 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

新生代何时晋升到老年代?

NmcYaMowyK.jpg
326cb3577f1a81984c932731d881717.png
NmcYaMowyK.jpg
空间分配担保是为了确定在MinorGC前确保老年代本身还有容纳新生代所有对象的剩余空间

类加载过程

(下图为类的生命周期)
28e963e4b9ca1922bdbe4590e925efb.png

类加载器

作用:所有的类都由类加载器加载,作用是将class文件加载到内存。

05yxlcN2em.jpg

双亲委派模型

每当一个类加载器接收到加载请求时,它会先将请求转发给父类加载器。在父类加载器没有找到所请求的类的情况下,该类加载器才会尝试去加载。使用委派模型的目的为了避免类的重复加载。
应用程序类加载器->拓展类加载器->启动类加载器

c6f1ad30-2c4b-4cfd-9e14-b30591b9a2ae.jpeg

自定义类加载器?
自定义类加载器需要继承ClassLoader()方法,如果要打破双亲委派模型重写loadClass(),
如果不想打破重写就重写ClassLoader()类中的findClass()方法。

加载即获取类的二进制字节流,是可控性最强的阶段

死亡对象的判断方法

3d8f9b7d-791b-4da8-a385-b5c2b69d13b1.jpeg

垃圾回收分类

984d66c049ffa577f3d6facee4a9bbb.png

垃圾收集算法

c8591148-ba59-453d-a88f-d2b9f0139432.jpeg

jvm调优

(对于系统的优化思路一般是,先排查是否是数据库的问题,包括,索引是否合理,是否需要引进分布式缓存,是否需要分库分表),然后考虑是否是硬件能力不足导致,然后再是在应用层代码上进行排查并优化,
最后考虑jvm调优。

在理解JVM内存结构和各种垃圾收集器前提下,结合业务,调整参数来使应用正常运行。

指标:吞吐量,停顿时间,垃圾回收频率

基于这三个指标,我们可能需要调整:

内存区域的大小以及相关策略

堆内存大小、新生代占多少、老年代占多少、Survivor占多少、晋升老年代的条件等

参数(-Xmx:设置堆的最大值、-Xms:设置堆的初始值、-Xmn:表示年轻代的大小、-XX:SurvivorRatio:伊甸区和幸存区的比例等等)

(按经验来说:IO密集型的可以稍微把「年轻代」空间加大些,因为大多数对象都是在年轻代就会灭亡。
内存计算密集型的可以稍微把「老年代」空间加大些,对象存活时间会更长些)

选择合适的垃圾回收器,以及设置合适的参数

一、针对新生代的垃圾收集器:Serial New,Parallel Scavenge 和 Parallel New

Serial(siry) New:应用复制算法,简单高效,但会暂停程序导致停顿。
ParNew:是Serial的多线程版本,可以配合老年代的CMS工作
Parallel(拍落) Scavenge(死凯位置)应用复制算法,并行收集器,追求高吞吐量,高效利用CPU。
(吞吐量就是运行用户代码时间/(运行用户代码时间+gc时间)

二针对老年代的垃圾收集器:Serial Old 和 Parallel Old,以及CMS

 Serial Old:Serial GC的老年代版本,采用标记整理算法。
 Parallel Old:Parallel Scavenge的老年代版本,可配合Parallel Scavenge收集器达成在整体应用上吞吐量最大化
 CMS是基于标记清除算法实现的。
 优点:并发收集、低停顿。
 缺点:CMS对cpu资源敏感,在cpu数量较少时,可能因为占用一部分cpu资源导致程序变慢。
      cms无法处理浮动垃圾,可能出现”Concurrent Mode Failure“失败而导致Full GC
      基于清除算法,会产生内存碎片。
      

585bcb755a555aa7c2644d529efef05.png
三横跨新生代和老年代的垃圾收集器G1

89288122d0d3ec79ae8d04babd2c43d.png

四、ZGC(可伸缩低延迟垃圾收集器)

特点:

一、并发收集:吞吐量不会下降超过15%。(与G1相比)

二、低延迟:GC的停顿时间不会超过10ms。

三、大内存支持:既能处理几百MB的小堆,也能处理几个TB的堆。

四、动态空间压缩:会对堆进行动态的空间压缩,避免堆内存碎片化的问题,并减少内存浪费。

比如(-XX:+UseG1GC:指定 JVM 使用的垃圾回收器为 G1、-XX:MaxGCPauseMillis:设置目标停顿时间、-XX:InitiatingHeapOccupancyPercent:当整个堆内存使用达到一定比例,全局并发标记阶段 就会被启动等等)

遇到问题进行调优,可使用工具

通过jps命令查看Java进程基础信息(进程号、主类)。

通过jstat命令查看Java进程相关的信息,如类加载、编译相关信息,各个区域的GC情况。

通过jinfo命令来查看和调整Java进程的运行参数。

通过jmap查看进程的内存信息,并且将信息保存到文件,可利用MAT进行分析。

通过jstack命令来查看JVM线程信息,可用来排查死锁相关问题。

Arthas(阿里开源的诊断工具)涵盖命令并有可视化界面。

1a840e9dae8a068a9057f0571e33990.png

OOM的原因和解决

定义:

当JVM内存不足,没有空闲内存,并且垃圾收集器也不能提供更多内存,就会发生OOM。

原因

一、堆空间不足。存在内存泄漏问题;堆大小设置不合理;JVM处理引用不及时,导致内存无法回收。

二、对于虚拟机栈和本地方法栈,类似于不断递归且没有返回条件,不断压栈就会导致StackOverFlowError。
如果JVM试图拓展堆空间的时候失败,就会抛出OOM。

三、在老版JDK中,由于JVM堆永久代垃圾回收不积极,容易出现OOM。元数据区引入有所改善。

四、直接内存不足,会导致OOM。

解决

一、使用jps,jmp,MAT,等工具分析出频繁full gc的原因并定位到代码。

频繁full gc

原因:

一、高并发,数据量过大,每次Young GC过后存活对象过多,内存分配不合理,Survivor区过小,导致对象频繁进入老年代,触发Full gc。

二、系统一次性加载大量数据到内存,导致大对象过多,大对象进入老年代,触发FULL GC。

三、系统内存泄漏,大量对象无法回收,一直占用老年代,触发FULL GC。

四、永久代加载类过多触发FUll GC。

五、代码或者第三方依赖包中有system.gc()操作,可设置JVM禁止执行该方法。

解决:

一、通过命令查看进程、线程情况、dump出内存快照,用MAT工具进行分析,确定原因。

二、调整JVM的参数,适当增大新生代的大小。

三、控制并发数量。

CPU打满?

原因:

一、代码中某个位置读取数据量较大,内存耗尽,频繁full gc,系统缓慢。

二、代码中有比较耗CPU的操作,导致CPU过高,系统运行缓慢。可通过命令查看当前CPU消耗高的进程和线程是哪一个,再查看线程的堆栈信息。

系统缓慢的情况

一、FULL GC次数过多

二、CPU打满

三、不定期出现的接口耗时情况。

eg:接口访问需要2、3秒才会返回,一般来说消耗的cpu和占用的内存也不高。思路是首先找到该接口,通过压测工具不断加大访问力度,由于访问力度大,大多数线程都会阻塞在该阻塞点,可以定位到接口中比较耗时的代码位置。

四、某个线程处于waiting状态。

比如CountDownLatch的不合理使用。

五、出现死锁。这个可以直接通过jstack日志分析得到。

三色标记法

作用:提高标记对象的效率

初始标记时STW时间较短,但并发标记时时间较长,因此应提高标记效率。

在三色标记中,从GC ROOT标记为以下三种颜色

白:在开始遍历时,所有对象都为白

灰:被垃圾回收器扫描过,但还有引用没有被扫描,为灰

黑:被垃圾回收器扫描过,并且这个对象的引用也全部被扫描,可存活对象,为黑。

全部扫描过后,回收为白的对象。

强软弱虚引用?

8a6e2a1c9bfd570ca3ac4f1a6386bbd.png

一个对象创建的过程

一个对象的流程图就如上图所示,大致上可以分为以下五步:

类检查机制(检查是否加载过类,没有加载过执行类加载过程)
分配内存
初始化
设置对象头
执行类加载的初始化步骤

Step1:类加载检查
虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。

对象的内存布局

在 Hotspot 虚拟机中,对象在内存中的布局可以分为 3 块区域:对象头、实例数据和对齐填充。
Hotspot 虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的运行时数据(哈希码、GC 分代年龄、锁状态标志等等),另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
实例数据部分是对象真正存储的有效信息,也是在程序中所定义的各种类型的字段内容。
对齐填充部分不是必然存在的,也没有什么特别的含义,仅仅起占位作用。 因为 Hotspot 虚拟机的自动内存管理系统要求对象起始地址必须是 8 字节的整数倍,换句话说就是对象的大小必须是 8 字节的整数倍。而对象头部分正好是 8 字节的倍数(1 倍或 2 倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

对象的访问定位

建立对象就是为了使用对象,我们的 Java 程序通过栈上的 reference 数据来操作堆上的具体对象。
对象的访问方式由虚拟机实现而定,目前主流的访问方式有:使用句柄、直接指针。
如果使用句柄的话,那么 Java 堆中将会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与对象类型数据各自的具体地址信息。
如果使用直接指针访问,reference 中存储的直接就是对象的地址。对象的访问定位-直接指针这两种对象访问方式各有优势。
使用句柄来访问的最大好处是 reference 中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。使用直接指针访问方式最大的好处就是速度快,它节省了一次指针定位的时间开销。HotSpot 虚拟机主要使用的就是这种方式来进行对象访问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/461397.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

01——LenNet网络结构,图片识别

目录 1、model.py文件 (预训练的模型) 2、train.py文件(会产生训练好的.th文件) 3、predict.py文件(预测文件) 4、结果展示: 1、model.py文件 (预训练的模型) impor…

Day17 深入类加载机制

Day17 深入类加载机制 文章目录 Day17 深入类加载机制一、初识类加载过程二、深入类加载过程三、利用类加载过程理解面试题四、类加载器五、类加载器分类六、类加载器之间的层次关系七、双亲委派模型 - 概念八、双亲委派模型 - 工作过程九、双亲委派模型 - 好处十、双亲委派原则…

Jmeter---分布式

分布式:多台机协作,以集群的方式完成测试任务,可以提高测试效率。 分布式架构:控制机(分发任务)与多台执行机(执行任务) 环境搭建: 不同的测试机上安装 Jmeter 配置基…

Sparse Convolution 讲解

文章目录 1. 标准卷积与Sparse Conv对比(1)普通卷积(2) 稀疏卷积(3) 改进的稀疏卷积(subm)2 Sparse Conv 官方API3. Sparse Conv 计算3. 1 Sparse Conv 计算流程3. 2 案例3.2.1 普通稀疏卷积3.2.2 subm模式的稀疏卷积3D点云数据非常稀疏,尤其体素化处理后(比如200k的点放…

【算法篇】七大基于比较的排序算法精讲

目录 排序 1.直接插入排序 2.希尔排序 3.直接选择排序 4.堆排序 5.冒泡排序 6.快速排序 7.归并排序 排序 排序算法的稳定性:假设在待排序的序列中,有多个相同的关键字,经过排序后,这些关键字的先后顺序不发生改变&#…

Spring项目问题—前后端交互:Method Not Allowed

问题 前后端交互时出现Method Not Allowed问题 Ajax中使用的是get,方法仍然出现post方法报错 Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method POST not supported] 浏览器中没有报错,只是接收不到后端返…

解锁数据潜力:OceanBase国产数据库学习不容错过的秘密!

介绍:OceanBase是一款由阿里巴巴和蚂蚁金服自主研发的通用分布式关系型数据库,它专为企业级应用而设计,具有金融级别的可靠性。以下是对OceanBase的详细介绍: 高可用性:OceanBase通过实现Paxos多数派协议和多副本特性&…

MySql入门教程--MySQL数据库基础操作

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

C语言从入门到熟悉------第四阶段

指针 地址和指针的概念 要明白什么是指针,必须先要弄清楚数据在内存中是如何存储的,又是如何被读取的。如果在程序中定义了一个变量,在对程序进行编译时,系统就会为这个变量分配内存单元。编译系统根据程序中定义的变量类型分配…

【滤波专题-第8篇】ICA降噪方法——类EMD联合ICA降噪及MATLAB代码实现(以VMD-ICA为例)

今天来介绍一种效果颇为不错的降噪方法。(针对高频白噪声) 上一篇文章我们讲到了FastICA方法。在现实世界的许多情况下,噪声往往接近高斯分布,而有用的信号(如语音、图像特征等)往往表现出非高斯的特性。F…

unity学习(60)——选择角色界面--MapHandler2-MapHandler.cs

1.新建一个脚本&#xff0c;里面有static变量loadingPlayerList using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace Assets.Scripts.Model {internal class LoadData{public static List<Pl…

3D地图在BI大屏中的应用实践

前言 随着商业智能的不断发展&#xff0c;数据可视化已成为一项重要工具&#xff0c;有助于用户更好地理解数据和分析结果。其中&#xff0c;3D地图作为一种可视化工具&#xff0c;已经在BI大屏中得到了广泛地应用。 3D地图通过将地理信息与数据相结合&#xff0c;以更加直观…

【AI】用iOS的ML(机器学习)创建自己的AI App

用iOS的ML(机器学习)创建自己的AI App 目录 用iOS的ML(机器学习)创建自己的AI App机器学习如同迭代过程CoreML 的使用方法?软件要求硬件开始吧!!构建管道:设计和训练网络Keras 转 CoreML将模型集成到 Xcode 中结论推荐超级课程: Docker快速入门到精通Kubernetes入门到…

计算机网络——物理层(数据通信基础知识)

计算机网络——物理层&#xff08;1&#xff09; 物理层的基本概念数据通信的基本知识一些专业术语消息和数据信号码元 传输速率的两种表示方法带宽串行传输和并行传输同步传输和异步传输 信道基带信号调制常用编码方式 我们今天进入物理层的学习&#xff0c;如果还没有了解OSI…

Transformer代码从零解读【Pytorch官方版本】

文章目录 1、Transformer大致有3大应用2、Transformer的整体结构图3、如何处理batch-size句子长度不一致问题4、MultiHeadAttention&#xff08;多头注意力机制&#xff09;5、前馈神经网络6、Encoder中的输入masked7、完整代码补充知识&#xff1a; 1、Transformer大致有3大应…

C++ 入门篇

目录 1、了解C 2、C关键字 2、命名空间 2.1 命名空间的定义 2.2 命名空间的使用 3. C输入与输出 4.缺省参数 4.1 缺省参数的概念 4.2 缺省参数的分类 5. 函数重载 5.1 函数重载的概念 5.2 C中支持函数重载的原理--名字修饰 6. 引用 6.1 引用概念 6.2 引用…

Docker 系列2【docker安装mysql】【开启远程连接】

文章目录 前言开始步骤1.增加mysql挂载目录2.下载镜像2.启动容器具体步骤4.无法连接5.测试连接 总结 前言 本文开始&#xff0c;默认已经安装docker&#xff0c;如果你还没有完成这个步骤&#xff0c;请查看这一篇文章【docker安装与使用】 开始步骤 1.增加mysql挂载目录 m…

网络原理(1)——UDP协议

目录 一、应用层 举个例子&#xff1a;点外卖 约定数据格式简单粗暴的例子 客户端和服务器的交互&#xff1a; 序列化和返序列化 xml、json、protobuffer 1、xml 2、json 3、protobuffer 二、传输层 端口 端口号范围划分 认识知名的端口号 三、UDP协议 端口 U…

宜搭faas服务器报错Network response was not OK

[error] https://api.dingtalk.com/v1.0/yida/forms/instances? fetch error Error: Network response was not OK 不出意外的话肯定是请求代码的某个部分出了问题&#xff1a;其中formInstanceId和updateFormDataJson是业务的内容 我检查过是没问题的。appType和systemToken…

面试经典-MySQL篇

一、MySQL组成 MySQL数据库的连接池&#xff1a;由一个线程来监听一个连接上请求以及读取请求数据&#xff0c;解析出来一条我们发送过去的SQL语句SQL接口&#xff1a;负责处理接收到的SQL语句查询解析器&#xff1a;让MySQL能看懂SQL语句查询优化器&#xff1a;选择最优的查询…