极简JVM结构图示

news2024/10/5 16:19:43

参考资料

  • JVM极简教程

JVM结构

  • JIT编译器,对于经常需要执行的字节码进行

类加载子系统

类加载器

tomcat的自定义类加载器

为了进行类的隔离,如果Tomcat直接使用AppClassLoader类加载类,那就会出现如下情况:

  • 应用A中有个com.example.Hello.class,应用B中也有个com.example.Hello.class,虽然都叫做Hello,但是具体的方法、属性可能不一样
  • 如果AppClassLoader先加载了应用A中的Hello.class,那么应用B中的Hello.class就不可能再被加载了,因为名字是一样
  • 就需要针对应用A和应用B设置各自单独的类加载器,也就是WebappClassLoader
  • 这样两个应用中的Helo.class都能被各自的类加载器所加载,不会冲突
  • 这就是Tomcat为什么用自定义类加载器的核心原因,为了实现类加载的隔离
  • JVM中判断一个类是不是已经被加载的逻辑是:类名+对应的类加载器实例

运行时数据区

程序计数器

  • 是物理寄存器的抽象实现
  • 用来记录待执行的下一条指令的地址3.它是程序控制流的指示器,循环、if else、异常处理、线程恢复等都依赖它来完成
  • 解释器工作时就是通过它来获取下一条需要执行的字节码指令的
  • 唯一一个在JVM规范中没有规定任何OutOfMemoryError情况的区域

虚拟机栈(java方法栈)

每个线程在创建时都会创建一个虚拟机栈,栈内会保存一个个的栈帧,每个栈帧对应一个方法。

  • 虚拟机栈是线程私有的
  • 一个方法开始执行栈帧入栈、方法执行完对应的栈帧就出栈,所以虚拟机栈不需要进行垃圾回收
  • 虚拟机栈存在OutOfMemoryError,以及StackOverflowError
    • 线程太多就可能会出现DutOfMemoryError,即线程创建时没有足够的内存去创建虚拟机栈
    • 方法调用层次太多,就可能会出现StackOverflowError
  • 可以通过-Xss来设置虚拟机栈的大小

栈帧结构

操作数栈(操作栈),栈帧中的一部分,用来在执行字节码指令过程中用来进行计算

public static void main(Stringp[] args){
	int a = 10;
	int b = 20;
	int c = a + b;
}
  • bipush,压栈10
  • istore_1,从操作数栈存储到局部变量表1(a)
  • iload_1,从局部变量读取变量1到栈
  • iadd,加法操作
  • return,方法执行完毕,栈帧清空

本地方法栈

  • 本地方法:native method,在java中定义的方法,但由其他语言实现
  • 虚拟机栈存的是java方法调用过程的栈帧,本地方法栈存的是本地方法调用过程中的栈帧。
  • 线程私有的,也可能会出现OOM和SOF

堆区

堆是VM中最重要的一块区域,JVM规范中规定所有的对象和数组都应该存放在堆中,在执行字节码指令时会把创建的对象存入堆中,对象对应的引用地址存入虚拟机栈中的栈帧中。当方法执行完之后,刚刚所创建的对象并不会立马被回收,而是要等JVM后台执行GC后,对象才会被回收。

  • -Xms,ms(memory start),指定堆的初始化内存大小,等价于-XX:InitialHeapSize
  • -Xmx,mx(memory max),指定堆的最大内存大小,等价于-XX:MaxHeapSize
  • 一般会把-Xms-Xmx设置为一样,这样VM就不需要在GC后去修改堆的内存大小了,提高了效率
  • 默认情况下,初始化内存大小=物理内存大小/64,最大内存大小=物理内存大小/4

新生代存储刚刚创建的对象,老年代存储经过垃圾回收之后仍然存活的对象

  • 可以通过-XX:NewRatio参数来配置新生代和老年代的比例,默认为2,表示新生代占1,老年代占2,也就是新生代占堆区总大小的1/3
  • 一般是不需要调整的,只有明确知道存活时间比较长的对象偏多,那么就需要调大NewRatio,从而调整老年代的占比

新生代又分为

  • Eden:伊甸园区,新对象都会先放到Eden区(除非对象的大小都超过了Eden区,那么就只能直接进老年代)
  • S0、S1:Survivor0、Survivor1区,也可以叫做from区、to区,用来存放MinorGC(YGC)后存在的对象
  • 默认情况下(Eden区:S0区:S1区)的比例关系为(8:1:1),也就是Eden区占新生代大小的8/10,可以通过-XX:SurvivorRatio来调整

总体过程如下

  • 新对象会创建在Eden区,当创建新对象无法在Eden存储时(已满),就会触发YGC(新生代垃圾回收)
  • 经过一轮gc后仍然存活的对象会存放到s0区
  • 新对象仍旧创建在Eden区,经过第二次垃圾回收后,仍旧存活的对象(包括Eden中的对象)被存放在s1区
  • 下一次s1中没有经过gc的对象会存储到s0区,s0和s1之间不断交换
  • 当超出一定gc次数的时候,对象被存储到老年代

如果Eden对象太大无法存储在s0和s1中,也会直接转移到老年代

对于超大对象,不会在Eden创建,直接存储到老年代

垃圾回收器

  • Young GC/Minor GC:负责对新生代进行垃圾回收

  • Old GC/Major GC:负责对老年代进行垃圾回收,目前只有CMS垃圾收集器会单独对老年代进行垃圾收集,其他垃圾收集器基本都是整堆回收(Full GC)的时候对老年代进行垃圾收集

  • Full GC:整堆回收,也会堆方法区进行垃圾收集

垃圾指在JVM中没有任何引用指向的对象,不清理就会导致持续的内存占用(无法给其他对象使用),最终OOM

垃圾回收方式

  • 引用计数法
  • 可达性分析法

引用计数法

每个对象都保存一个引用计数器属性,用户记录对象被引用的次数。

  • 优点,实现简单,计数器为0则表示是垃圾对象

  • 缺点,需要额外的空间来存储引用计数,以及需要额外的时间来维护引用计数,但是无法处理循环引用的问题

可达性分析法

以GC Roots作为起始点,然后一层一层找到所引用的对象,被找到的对象就是存活对象,那么其他不可达的对象就是垃圾对象。

GC Roots是一组引用,包括:

  • 线程中虚拟机栈中正在执行的方法中方法参数、局部变量所对应的对象引用
  • 线程中本地方法栈中正在执行的方法中方法参数、局部变量所对应的对象引用
  • 方法区中保存的类信息中静态属性所对应的对象引用
  • 方法区中保存的类信息中常量属性所对应的对象引用
  • 等等

垃圾回收算法

标记清除(Mark-Sweep)算法

一种非常基础和常用的垃圾回收算法,针对某块内存空间,比如新生代、老年代,如果可用内存不足后,就会STW(Stop the world,在执行垃圾回收的过程冻结所有用户线程的运行,直到垃圾回收线程执行结束),暂定用户线程的执行,然后执行算法进行垃圾回收:

  1. 标记阶段:从GC Roots开始遍历,找到可达对象,并在对象头中进行记录
  2. 清除阶段:堆内存空间进行线性遍历,如果发现对象头中没有记录是可达对象,则回收它

缺点,效率不高,会产生内存碎片

优点,思路简单

复制(Copying)算法

将内存空间分为两块,每次只使用一块。在进行垃圾回收时,将可达对象复制到另外没有被使用的内存块中,然后再清除当前内存块中的所有对象,后续再按同样的流程进行垃圾回收,交替进行。

优点:

  • 没有标记和清除阶段,通过GC Roots找到可达对象,直接复制,不需要修改对象头效率高
  • 不会出现内存碎片

缺点:

  • 需要更多的内存,始终有一半的内存空闲
  • 对象复制后,对象存放的内存地址发生了变化,需要额外的时间修改栈帧中记录的引用地址
  • 如果可达对象比较多,垃圾对象比较少,那么复制算法的效率就会比较低,所以垃圾对象多的情况下(Eden区),复制算法比较适合

标记-整理(Mark-Compact)算法

分为三个阶段

  1. 和标记清除算法一样,从GC Roots找到并标记可达对象
  2. 将所有存活对象移动到内存的一端
  3. 最后清理边界外所有的空间

标记整理算法相当于标记清除算法执行完一次之后再进行一次内存整理
优点:

  • 不会出现内存碎片
  • 不需要利用额外的内存空间

缺点:

  • 效率要低于标记清除算法、复制算法
  • 需要修改栈帧中的引用地址

垃圾回收算法的比较

Mark-SweepMark-CompactCopying
速度中等最慢最快
空间开销少(有碎片)少(无碎片)最多
移动对象

分代收集算法(理念)

不同对象的存活时长是不一样的,也就可以针对不同的对象采取不同的垃圾回收算法。

默认几乎所有的垃圾收集器都是采用分代收集算法进行垃圾回收的。

我们会把堆分为新生代和老年代:

  • 新生代中的对象存活时间比较短,那么就可以利用复制算法,它适合垃圾对象比较多的情况。
  • 老年代中的对象存活时间比较长,所以不太适合用复制算法,可以用标记-清除或标记-整理算法,比如:
    • CMS垃圾收集器采用的就是标记-清除算法
    • Serial Old垃圾收集器采用的就是标记-整理算法

常见垃圾收集器

CMS(并发标记清除算法)

下图中蓝色表示用户线程,橙色表示gc线程

CMS整个垃圾收集过程更长了,但是STW的时间变短了

在垃圾收集过程中大部时间用户线程也还在执行,所以用户体验更好了,但是吞吐量更低了(单位时间内执行的用户线程更少了)

(1)初始标记:STW,暂停所有工作线程,然后标记出GC Roots能直接可达的对象。一旦标记完,就恢复工作线程继续执行,这个阶段比较短

(2)并发标记:从上一个阶段标记出的对象,开始遍历整个老年代,标记出所有的可达对象。耗时会比较长,但是不需要STW,用户线程与垃圾收集线程一起执行。三色标记

(3)重新标记:上个阶段标记的对象,可能有误差,需要进行修正需要STW,但是时间也不是很长。增量更新

(4)并发清除:重置标记方便下次gc,删除垃圾对象由于不需要移动对象,这个阶段也可以和用户线程一起执行,不需要STW

concurrent mode failure

如果在并发标记、并发清理过程中,由于用户线程同时在执行,如果有新对象要进入老年代,但是空间又不够,那么就会导致"concurrent mode failure”(垃圾回收速度跟不上创建对象的速度),此时就会利用Serial Old来做一次垃圾收集,就会做一次全局的STW。

在并发清理过程中,可能产生新的垃圾,这些就是“"浮动垃圾”,只能等到下一次GC时来清理

由于采用的是标记-清除,所以会产生内存碎片,可以通过参数-XX:+UseCMSCompactAtFullCollection可以让VM在执行完标记-清除后再做一次整理,也可以通过-XX:CMSFullGCsBeforeCompaction来指定多少次GC后来做整理,默认是O,表示每次GC后都整理。

G1垃圾回收算法

  • 每一个方块叫做region,堆内存会分为2048个region,每个region的大小等于堆内存除以2048

  • 仍旧区分了Eden区、S0区、S1区、老年代,只不过空间可以是不连续的了(逻辑连续,物理分离)

  • Humongous区是专门用来存放大对象的(如果一个对象大小超过了一个region的50%,那么就是大对象

(1)初始标记(同CMS的初始标记阶段):STW,暂停所有工作线程然后标记出GC Rootsi能直接可达的对象一旦标记完,就恢复工作线程继续执行,这个阶段比较短

(2)并发标记(同CMS的初始标记阶段):从上一个阶段标记出的对象,开始遍历整个老年代,标记出所有的可达对象耗时会比较长但是不需要STW,用户线程与垃圾收集线程一起执行。三色标记

(3)最终标记(同CMS的重新标记):上个阶段标记的对象,可能有误差,需要进行修正需要STW,但是时间也不是很长原始快照

(4)筛选回收(类似CMS的并发清除阶段)需要STW,来清除垃圾对象可以通过-X:MaxGCPauseMillis:来指定GC的STW停顿的时间(并非按照垃圾对象的数量进行gc,而是按照指定的时间执行gc),所以可能并不会回收掉所有垃圾对象,默认200ms采用的复制算法。不会产生碎片(会把某个region.里的对象复制到另外空闲regionl区域,比如相邻的)

YoungGC:Eden区满,就会触发G1的YoungGC,对Eden区进行

GC MixedGC:老年代的占用率达到了-XX:InitiatingHeapOccupancyPercent指定的百分比,回收所有的新生代以及部分老年代,以及大对象区

FullGC:在进行MixedGC:过程中,采用的复制算法,如果复制过程中内存不够,则会触发FullGC,会STW,并采用单线程来进行标记-整理算法进行GC,相当于用一次Serial GC

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

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

相关文章

Android中Binder在项目中的具体使用详解

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂,风趣幽默",感觉非常有意思,忍不住分享一下给大家。 👉点击跳转到教程 前言:Binder的介绍 在 Android 中,Binder 是一种跨进程通信&…

静默安装oracle

oracle依赖环境包 一、创建用户属组 [rootlocalhost ~]# groupadd oinstall[rootlocalhost ~]# groupadd dba[rootlocalhost ~]# groupadd oper[rootlocalhost ~]# useradd -g oinstall -G dba,oper oracle[rootlocalhost ~]# passwd oracle #修改oracle用户密码 二、创建目录…

二叉搜索树(BST)详解及代码实现

推荐可视化插入、删除节点的二叉树网站:Binary Search Tree Visualization (usfca.edu) 1. 概述 二叉搜索树(Binary Search Tree,简称BST)是一种特殊的二叉树结构,它具有以下特点: 有序性:对于…

Eureka入门 ; 服务注册中心,服务注册服务发现;SpringCloud eureka

一、引入 Spring Cloud封装了netflix公司的Eureka模块来进行实现服务治理。 在传统的RPC远程调用框架中,管理每个服务服务之间依赖关系比较复杂,所以需要服务治理,管理服务之间的依赖。可以实现服务注册、调用、负载均衡、容错等技术。 1. 服…

2023九坤投资暑期实习笔试复盘

5.22号笔试,5.24确认自己笔试挂。想想这也是自己第一次做量化私募基金的笔试,在此复盘一下。情况:北邮本硕。但开始准备暑期准备的比较晚,4月初才开始一边刷题一边投简历,所以手撕算法不太强,但运气和灵感好…

ChatGPT除了模型, 各个大厂、中厂、小厂们还在卷什么?

ChatGPT 问世后,各大公司都在「大模型」上下了苦功,模型能力也成为大家最关注的话题。ChatGPT 虽直接定义了基于大模型的生成式对话机器人这个产品类型,其模型的强大也导致大家都忽略了它在产品使用上的问题。 其实不管是底层模型开发的大厂…

印尼市场入门指南:品牌如何在当地获得市场份额?

2023年,印尼成为了全球最大的新兴市场之一。印尼是东南亚最大的经济体,拥有庞大的人口和潜在的消费市场,吸引着越来越多的国际品牌进入。根据预测,印尼的消费支出将在2023年达到1.3万亿美元,成为亚洲增长最快的消费市场…

个人博客搭建详细步骤

1. 安装 jdk 和 tomcat 下面将带大家安装 jdk 和部署 tomcat; 首先在本地下载好 jdk 和 tomcat 安装压缩包在服务器新建一个目录,比如在服务器新建一个目录 soft,上传 jdk, tomcat 到服务器 mkdir soft cd soft rz 选择上传的文件名称 //上传文件新建…

【windows脚本】使用diskpart命令管理未分配磁盘

环境 系统:win10 x64 概述 使用windows脚本管理未分配磁盘,手动操作需要做以下几步: 1、初始化磁盘GPT形式; 2、新建简单卷,设置大小和驱动器号。 3、格式化。 diskpart命令 使用diskpart工具,命令如…

PNAS| 绘制人脑发育曲线:横断面研究低估了人脑变化

文章目录 第一部分:横断面数据低估了与年龄相关的大脑变化。第二部分:横截面规范模型最小限度地帮助个体化预测。第三部分:非年龄相关因素对于预测个体变化的误差起到了贡献作用。参考 **按:**研究人脑毕生发展对于理解常见的精神…

springboot应用程序并发请求达到多少会被拒绝

文章目录 前言内嵌服务器tomcat测试 undertow 前言 前几天刷B站看到了一个问题,感觉挺有意思的,“忽略接口本身性能,springboot应用程序能处理多少请求不被拒绝?”,今天便来探一探这个问题 本文主要重点是侧重于spri…

matplotlib常用函数总结

文章目录 1.IDE里的1.1 显示模式(plt.ion()和plt.ioff())1.2 backend说明 2 jupyter里的3 通用的3.1 cmap3.2 subplot()相关3.3 绘制动态图(Animation类)3.4 matplotlib利用rcParams配置样式参数 4. 与opencv连用可能遭遇的问题1.…

迭代器的设计原则

iterator必须提供5种associated types 1.iterator_category 2.value_type 3.diiference_type 4.pointer 5.reference 对于iterator_category来说,例如双向链表:typedef bidirectional_iterator_tag iterator_category;算法和迭代器的关系: 算法提问&a…

WAV 格式和音频裁剪、转码处理

文章目录 0、参考资料1、WAV 格式了解1.1 WAV 文件头1.2 RIFF Chunk 区块1.3 Format Chunk 区块1.4 Data Chunk 区块 2、音频剪裁 -> 解码 -> 编码2.1 mp32.1.1 裁剪2.1.2 解码2.1.3 编码 2.2 pcm 裁剪 0、参考资料 【音频处理】WAV 文件格式分析 ( 逐个字节解析文件头 …

用友BIP新一代全球司库,重塑企业资金管理新价值

资金是企业有效推进业务运营与发展并赖以生存的血液和养料,资金管理是企业财务管理的核心职能,在《“十四五”中央企业发展规划纲要》中明确央企要将集团资金管理业务规划置于重要战略位置。而国资委1号文发布,则进一步强调司库建设对中央企业…

2核2G3M腾讯云轻量应用服务器CPU性能测评

阿里云轻量应用服务器2核2G3M带宽一年95元,100%CPU性能,3M带宽下载速度384KB/秒,40GB SSD系统盘,月流量200GB,折合每天6.6GB流量,超出月流量包的流量按照0.8元每GB的支付流量费,地域节点可选广州…

vue+springboot前后端分离项目整合部署流程

我们在进行前后端分离开发的时候,一般是将前端项目部署到nginx服务器上,与后端项目分开部署,但是如果是个人开发的小型项目,不需要这么麻烦,直接将前后端项目放到一起部署即可。 本文就来介绍一下前后端项目一起部署的…

第一章 部署DHCP服务

♥️作者介绍:奇妙的大歪 ♥️个人名言:但行前路,不负韶华! ♥️个人简介:云计算网络运维专业人员 目录 DHCP:动态主机配置协议 1.DHCP的优点 2.DHCP的分配方式 3.DHCP的工作原理(租约过程…

winows搭建远程仓库Github(linux通用)

winows搭建远程仓库Github(linux通用) 文章目录 winows搭建远程仓库Github(linux通用)创建远程仓库配置SSH克隆项目多人协同开发代码冲突标签分支 创建远程仓库 以下操作为演示在Github网站上创建远程仓库 1.登陆注册Github 2.创…

Linux知识点 -- 进程概念(二)

Linux知识点 – 进程概念(二) 文章目录 Linux知识点 -- 进程概念(二)一、进程优先级1.概念2.进程中的优先级信息3.更改进程优先级4.进程切换 二、环境变量1.概念2.常见的环境变量3.环境变量相关命令4.通过代码获取环境变量5.环境变…