JVMJava虚拟机

news2024/11/19 6:43:15

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.coloradmin.cn/o/1521352.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python—gui-计算图像像素两点间距离

代码: import tkinter as tk from tkinter import ttkdef create_gui():# 创建Tkinter窗口root tk.Tk()# 设置窗口标题root.title("显示图片")# 图片文件路径image_path path_to_your_image.jpg# 加载图片img load_image(image_path)# 创建标签&#…

产品推荐 - ALINX XILINX FPGA开发板 Artix-7 XC7A100T-2FGG484I

01开发板介绍 此款开发板采用核心板扩展板的模式,方便用户对核心板的二次开发利用。FPGA使用的是Xilinx公司的ARTIX-7系列的芯片,型号为XC7A100T-2FGG484I。在核心板使用了2片MICRON公司的MT41J256M16HA-125 DDR3芯片,组合成32bit的数据总线…

联想拯救者刃7000K2024游戏电脑主机仅售6999元

这款联想拯救者刀锋7000K 2024游戏电脑主机在京东促销中售价仅为6999元,相比原价7499元有相当大的折扣。 这是一款功能强大的游戏电脑,配备了全新的 15-14400(F) 处理器和 RTX™ 4060 显卡,以及 16GB DDR5 内存和 1TB 固态硬盘。 外观方面&a…

STL_vector简化模拟—详解深层次深拷贝问题

文章目录 迭代器框架和成员变量基础成员函数容量相关的成员函数关于深拷贝中的深拷贝问题operator[ ]重载和内容修改函数类模板内的嵌套类型全部代码 根据原码看出vector的成员并不像string类的一个指针加一个size和一个capacity。 而是三个指针,_start , _finish ,…

IntelliJ IDEA 面试题及答案整理,最新面试题

IntelliJ IDEA中的插件系统如何工作? IntelliJ IDEA的插件系统工作原理如下: 1、插件架构: IntelliJ IDEA通过插件架构扩展其功能,插件可以添加新的功能或修改现有功能。 2、安装和管理: 通过IDEA内置的插件市场下载…

【海贼王的数据航海】排序——直接选择排序|堆排序

目录 1 -> 选择排序 1.1 -> 基本思想 1.2 -> 直接选择排序 1.2.1 -> 代码实现 1.3 -> 堆排序 1.3.1 -> 代码实现 1 -> 选择排序 1.1 -> 基本思想 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置&…

springCloudeAlibaba的使用

父pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…

【Docker篇】数据卷相关操作

文章目录 &#x1f388;前言&#x1f354;数据卷&#x1f6f8;操作命令⭐创建一个数据卷&#xff0c;并查看数据卷在宿主机的目录位置 &#x1f339;挂载数据卷 &#x1f388;前言 在前面文章的nginx案例中&#xff0c;修改nginx的html页面时&#xff0c;需要进入nginx内部。并…

k8s-高可用etcd集群 26

reset掉k8s2&#xff0c;k8s3&#xff0c;k8s4节点 清理完网络插件后重启 快速创建一个k8s集群 修改初始化文件 添加master节点 备份 查看etcd配置 启动docker 将etcd二进制命令从容器拷贝到本机 备份 查看快照状态 删除集群资源 恢复 停掉所有的核心组件 从快照恢复 重启所有…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:StepperItem)

用作Stepper组件的页面子组件。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 支持单个子组件。 接口 StepperItem() 属性 参数名参数类型参数描述prevLabelstring设置左侧文本按钮内…

python 统计中国观鸟记录中心官网已观测的鸟类种类

python 统计中国观鸟记录中心官网已观测的鸟类种类 中国观鸟记录中心网站&#xff1a;https://www.birdreport.cn/ 先下载官网 Excel 文件 文件放置目录如下&#xff1a; home dataset xxx.xlsxxxx.xlsxxxx.xlsx Excelgrep.py &#xff08;进行文件内容提取的程序&#xff…

day-21 前 K 个高频元素

思路&#xff1a;用ans[]存储频次最高的k个元素&#xff0c;用anslen[]存储对应的索引&#xff0c;将nums进行排序依次统计每个元素出现次数&#xff0c;再判断是否需要对ans[]和anslen[]进行替换&#xff0c;最后ans即为答案 注意点&#xff1a;遍历结束后&#xff0c;还需要…

数据库引论:2.SQL简介

SQL(Structured Query Language,结构化查询语言) 2.1 SQL查询语言概览 SQL语言包含 数据定义语言(Data-Definition Language,DDL)。SQL DDL提供定义关系模式、删除关系以及修改关系模式的命令。数据操纵语言(Data-Manipulation Language,DML)。SQL DML提供从数据库中查询信息…

【算法】AC自动机的优化:增量更新与删除

一、概述 AC自动机&#xff08;Aho-Corasick Automation&#xff09;是著名的多模匹配算法&#xff0c;源于贝尔实验室&#xff0c;并且在实际应用中得到广泛的引用&#xff0c;且具有以下特点&#xff1a; 只需要扫描一次文本&#xff0c;即可获取所有匹配该文本的模式串复杂…

小红书根据关键词取商品列表 API 返回值说明

小红书根据关键词取商品列表的API返回值通常包含与搜索请求相关的商品列表信息。这些信息包括匹配到的商品列表、商品详情、排序方式等。以下是一个简化的示例&#xff0c;展示了小红书根据关键词取商品列表API可能返回的JSON格式数据&#xff1a;获取调用详情链接 item_searc…

王道机试C++第8章递归与分治 Day35和蓝桥杯两道真题程序

第 8 章 递归与分治 递归是指&#xff1a;函数直接或间接调用自身的一种方法&#xff0c;通常可把一个复杂的大型问题层层转化为与原问题相似但规模较小的问题来求解。 递归策略只需少量的程序就可描述解题过程所需的多次重复计算&#xff0c;因此大大减少了程序的代码量。 8.…

一个命令查看自己的WIFI密码

一个命令查看自己的WIFI密码 忘记wifi密码怎么办&#xff1f;一个命令查看自己的wifi密码。 一、打开命令行 使用快捷键“WinR”&#xff0c;打开运行窗口&#xff0c;输入“cmd”后回车即可。 二、输入命令network shell命令 输入命令network shell&#xff0c;简称netsh&…

Android 面试题及答案整理,最新面试题

Android中Intent的作用及分类 Intent在Android中用作组件之间传递信息&#xff0c;它可以用于启动活动(activity)、服务(service)和发送广播(broadcast)。Intent主要分为显式Intent和隐式Intent两大类。 1、显式Intent&#xff1a; 直接指定了要启动的组件名称&#xff08;比如…

【网络】详解HTTPS及探究加密过程

目录 一、什么是HTTPS1、加密解密是什么2、为什么要加密3、常见的加密方式1、对称加密2、非对称加密 二、探究HTTPS如何实现加密1、方案一----只使用对称加密2、方案二----只使用非对称加密3、方案三----双方都使用非对称加密4、方案四----非对称加密 对称加密5、中间人攻击6、…

企业微信 API 接口调用教程:深入解析企业微信 API 的用法

本文通过 access_token 凭证的方式来讲解怎么调用 企业微信 API&#xff0c;并一步步介绍如何获取企业微信 API 的 corpsecret、corpid、access_token 凭证以及怎么向企业微信的应用发送消息。 企业微信 API 在线地址为&#xff1a;qiyeweixin.apifox.cn/ &#xff0c;这个在线…