简述JVM
文章目录
- JVM简介
- JVM运行时数据区
- 堆(线程共享)
- 方法区/元空间/元数据区(线程共享)
- 栈
- 程序计数器
- JVM类加载
- 类加载过程
- 双亲委派模型
- 垃圾回收机制(GC)
- 判断对象是否为垃圾
- 判断是否被引用指向
- 如何清理垃圾, 释放对象?
JVM简介
JVM 是 Java Virtual Machine 的简称, 意为Java虚拟机.
虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。
JVM运行时数据区
也就是JVM的内存布局

堆(线程共享)
保存程序中创建的对象
方法区/元空间/元数据区(线程共享)
存放被JVM加载的类信息(类对象), 常量, 静态变量(static), 即时编译器编译后的代码等数据
栈
存放方法的调用关系, 局部变量
程序计数器
记录了当前线程执行的下一条指令的内存地址
class Test {public int n = 20;public static int a = 10;
}
public class Main() {public static void main(String[] arg) {Test t = new Test();}
}
n是普通的成员变量, 就包含在new的对象的内部, 存放在堆上
a是一个静态成员变量, 包含在类对象中, 存放在方法区中
t是一个局部变量, 存放在栈上
new Test()这个对象是保存在堆上的
栈上的t保存了堆上的new Test()的内存地址
JVM类加载
Java程序一开始是一个.java文件, 通过javac编译成.class文件, 运行java程序, JVM就会读取.class文件, 把文件的内容加载到内存中, 并构造成一个.class对象
类加载就是: 把类从硬盘文件加载到内存中.
类加载过程
流程:
-
加载: 找到.class文件, 打开文件, 并读取文件内容, 并且尝试解析格式
-
验证: 检查当前.class文件是否符合标准格式
-
准备: 给类对象分配内存. 分配出来的内存空间, 内容就是全0的值.
-
解析: 将常量池内的符号引用替换为直接引用的过程, 也就是初始化常量的过程. 初始化类对象中涉及到的一些字符串常量, 这些字符串常量在.class文件中已经存在, 直接读到内存中就行.
- 符号引用: 偏移量. 在.class文件中不知道字符串真实的内存地址在哪, 只知道一个相对的偏移量, 知道字符串的内容在.class文件的哪个地方.
- 直接引用: 真实的内存地址
-
初始化: 对类对象进行更具体的初始化操作. 初始化金泰城园, 执行静态代码块, 加载父类…
双亲委派模型
实则单亲.
JVM加载.class文件的时候, 需要用到"类加载器"模块.
JVM中自带了三个类加载器:
- Bootstrap ClassLoader: 负责加载标准库中的类
- Extension ClassLoader(父亲是Bootstrap ClassLoader): 负责加载JVM扩展的库
- Application ClassLoader(父亲是Extension ClassLoader): 负责加载第三方库.
不是父类子类的继承关系, 而是对象里有一个parent引用指向 父 类加载器 实例
当接收到类加载请求时:
- Application ClassLoader是类加载的入口, 不会立即就搜索第三方库的目录, 而是先把任务委派给父亲, 让父亲先尝试加载.
- 到了Extension ClassLoader, 也不会立即搜索扩展库的目录, 把任务委派给父亲, 让父亲先尝试加载.
- 到了Bootstrap ClassLoader, 也不会立即搜索扩展库的目录, 把任务委派给父亲, 但是他没有父亲, 就只能自己来搜索了. 如果找到了这个类, 就会进行后续的加载流程; 如果没有, 那么任务就会交付给孩子来解决.
- 如果任务回到了Extension ClassLoader, 他就要搜索扩展库的目录, 如果找到了这个类, 就会进行后续的加载流程; 如果没有, 那么任务就会交付给孩子来解决.
- 如果任务回到了Application ClassLoader, 他就要搜索第三方库的目录, 如果找到了这个类, 就会进行后续的加载流程; 如果没有, 那么就抛出异常.
这样做的目的: 明确类的优先级(标准库的类最优先加载, 扩展库其次, 第三方库最低)
标准库中有一个类java.lang.String, 如果我们自己也写了一个java.lang.String类
JVM始终是加载标准库里的类, 而不会加载到我们写的类, 这样便可以避免程序员的代码对标准库的代码产生负面影响
类加载的时机?(类似于懒汉模式, 用到了才加载)
- 构造了这个类的实例
- 使用了该类的静态方法, 静态属性
- 子类的加载会触发父类加载.
垃圾回收机制(GC)
对于程序计数器, 栈而言, 它的生命周期与相关的线程有关, 随线程生, 随线程灭, 并且这两个区域的内存分配和回收具有确定性, 因为当方法或者线程结束了, 内存就自然跟着线程回收了. 所以垃圾回收主要是回收堆和方法区这两个区域.
缺点: 消耗额外的系统资源, 消耗一定的时间, 可能有STW问题
垃圾回收是以对象为单位进行回收
垃圾回收的流程分为两步: 1. 判定对象是否为垃圾. 2. 释放对象的内存
判断对象是否为垃圾
一个对象, 如果在后续代码中不会被继续使用到了, 就可以视作是垃圾了
-
不会被继续使用: 没有被任何引用指向
public void test() {T t = new T();t.func(); } test();调用方法test的时候, 局部变量t被创建, 当test方法执行完了之后, t自然销毁, 此时
new T()就没有被引用指向了, 这个对象也就是垃圾了.
判断是否被引用指向
-
引用计数
给这个对象里面安排一个计数器, 每次有引用指向它, 就把计数器+1, 每次引用被销毁, 计数器-1, 当计数器为0, 意味着该对象就是垃圾了
class Test {// } Test t = new Test();//new Test()里的计数器为1 Test t2 = t;//new Test()里的计数器为2 Test t3 = t2;//new Test()里的计数器为3 t = null;//new Test()里的计数器为2 t2 = null;//new Test()里的计数器为1 t3 = null;//new Test()里的计数器为0, 此时该对象为垃圾了该方法并非是JVM中使用的方案, Python和PHP的虚拟机GC采用的是此方案
缺陷:
-
空间利用率低, 浪费更多的内存空间
-
可能存在循环引用的问题, 导致对象不能正确识别为垃圾.
class Test {public Test t; } Test a = new Test();//计数器为1 Test b = new Test();//计数器为1 a.t = b;//计数器为2 b.t = a;//计数器为2 a = null;//计数器为1 b = null;//计数器为1
此时这两个对象的引用计数不为0, 不能被当做垃圾. 与此同时, 一想要使用对象1, 就需要访问对象2. 要想使用对象2, 就得先访问到对象1…这就是循环引用
-
-
可达性分析(JVM使用的方案)
JVM首先会从现有代码中的能直接访问到的对象出发, 尝试便利所有能访问的对象, 只要对象能访问到, 就会标记成"可达", 完成整个遍历之后, 不可达的对象, 就相当于是垃圾了.
这样的操作没有额外的空间开销, 但是消耗了更多的时间.
那些是能直接访问到的对象呢?
这些对象又被称为gc roots.
- 栈上的局部变量.
- 常量池里的引用
- 方法区中类静态属性引用的对象
- 本地方法栈中 JNI(Native方法)引用的对象
代码执行过程中, 一个对象是否是垃圾, 往往是动态变化的(之前不是垃圾, 现在是垃圾了), 所以可达性分析的扫描是持续的周期性的
如何清理垃圾, 释放对象?
-
标记清除: 被标记为垃圾的对象直接清除.
弊端: 申请内存的时候, 都是申请的连续的空间, 直接释放会导致内存的碎片化, 会破环原有的连续性, 可能会导致有内存, 但是申请不了.
-
复制算法: 通过冗余的内存空间, 把有效的对象复制到另一部分空间, 避免内存碎片.
把一个内存分成两份, 一份使用, 一份等待有效对象被复制过来.
弊端: 如果复制的对象多, 开销会很大, 而且内存利用率也不高, 相当于浪费了一般的内存.
-
标记整理: 类似于顺序表的删除元素操作.
弊端: 这样的方式虽然解决了复制算法内存利用率低的问题, 但是搬运对象的成本也比较高.
-
分代回收: 采用分治的思想, 进行代的划分, 把不同生命周期的对象放在不同代上, 不同代上采用最适合它的垃圾回收方式进行回收.
Java的对象大体分为两类: 1. 生命周期很长的; 2.生命周期很短的
不同的对象的生命周期是不一样的. 因此, 不同生命周期的对象可以采取不同的收集方式, 以便提高回收效率.
如何分代?
JVM根据对象存活的周期(GC周期性扫描)不同, 把对内存划分了2块, 为新生代和老年代.
新生代又分为伊甸区(Eden)和幸存区(Survivor).
伊甸区占大部分内存, 这里存储的对象生命周期都很短. 经过一次GC后, 存活下来的对象就会通过复制算法复制到幸存区.
幸存区是两块大小相等的内存区域, 每次只用一块, 如果这里的对象经过GC后存货, 会继续被复制到另一块幸存区, 如此往复.如果一个对象在幸存区里经过了很多轮GC还存活, 证明它的生命周期很长, 那么它就会被复制到老年代.
老年代的GC频率比新生代要低. 这里清理垃圾的策略是标记整理
如果一个对象的体积很大, 那么他会直接进入老年代, 因为这样的对象不适合进行复制
相关文章:
简述JVM
文章目录 JVM简介JVM运行时数据区堆(线程共享)方法区/元空间/元数据区(线程共享)栈程序计数器 JVM类加载类加载过程双亲委派模型 垃圾回收机制(GC)判断对象是否为垃圾判断是否被引用指向 如何清理垃圾, 释放对象? JVM简介 JVM 是 Java Virtual Machine 的简称, 意为Java虚拟机…...
【多线程面试题 六】、 如何实现线程同步?
文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 面试官: 如何实现线程同步&…...
地面文物古迹保护方案,用科技为文物古迹撑起“智慧伞”
一、行业背景 当前,文物保护单位的安防系统现状存在各种管理弊端,安防系统没有统一的平台,系统功能不足、建设标准不同,产品和技术多样,导致各系统独立,无法联动,形成了“信息孤岛”。地面文物…...
k8s之Flannel网络插件安装提示forbidden无权限
一、问题描述 在安装k8s的网络插件时,提示如下信息,各种forbidden无权限 [rootzzyk8s01 scripts]# kubectl apply -f kube-flannel.yml Error from server (Forbidden): error when retrieving current configuration of: Resource: "policy/v1b…...
在微信小程序云开发中引入Vant Weapp组件库
介绍 Vant 是一个轻量、可靠的移动端组件库,于 2017 年开源。 目前 Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本,并由社区团队维护 React 版本和支付宝小程序版本。 介绍 - Vant Weapp (youzan.github.io) Vant Weapp需要安装 node.js&…...
Vue+ElementUI项目打包部署到Ubuntu服务器中
1、修改config/index.js中的assetsPublicPath: /,修改为assetsPublicPath: ./ assetsPublicPath: ./2、在build/utils.js中增加publicPath: ../../ publicPath: ../../3、打开终端,在根目录下执行npm run build进行打包,打包成功后会生成dist npm run…...
面试题收集——Java基础部分(一)
1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。 2、Java有没有goto? java中的保留字…...
Vue中this指向问题
文章目录 1 由Vue管理的函数2 不被Vue管理的函数3 总结 1 由Vue管理的函数 computed 计算属性watch 监视属性filters (Vue3中已弃用且不再支持) 过滤器methods 上述属性里配置的函数this指向Vue实例,不要采用箭头函数写法,因为箭头函数没有自己的this对…...
【iPad已停用】解锁教程
iPad多次输错密码时,会自动锁定并停用,这时候你可以使用iTuens或Tenorshare进行解锁。 一、使用iTunes解锁 下载并安装iTunes 使用数据线将iPad连接上电脑 让iPad进入恢复模式,同时安装iPad电源键和Home键,直到Logo出现也不要松…...
python不调用heapq库 实现大顶堆,小顶堆
参考了博客,并对其进行了堆的push() 和 降序排序的补充 【精选】图解堆排序及其Python实现_python 实现小顶堆-CSDN博客 目录 大顶堆 调用结果展示: 小顶堆: 调用结果展示: 此结果与调用heapq库中的heapify(arr)函数等效 …...
STM32F4X SDIO(二) SDIO协议
上一节简单介绍了SD卡的分类,本节将会介绍SD卡的通信协议,也就是SDIO协议。 STM32F4X SDIO(二)SDIO协议 SD 卡管脚和寄存器SD卡管脚分布SD卡通信协议SD卡寄存器SD卡内部结构 SDIO总线SDIO总线拓扑SDIO总线协议SDIO协议的基本结构…...
设计模式--7个原则
单一职责原则:一个类负责一项职责。 里氏替换原则:继承与派生的规则。 依赖倒置原则:高层模块不应该依赖基层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程࿰…...
AltiumDesigner原理图编译错误报告信息解释
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、ViolationsAssociated with Buses 有关总线电⽓错误的各类型(共 12 项)二、ViolationsAssociated Components 有关元件符号电⽓错误…...
使用 Visual Studio Code 编写 TypeScript程序
安装 TypeScript 首先,确保你已经安装了 TypeScript,如果没有安装,请参考https://blog.csdn.net/David_house/article/details/134077973?spm1001.2014.3001.5502进行安装 创建 新建一个文件夹,用vs code打开,在文…...
科大讯飞发布讯飞星火 3.0;开源AI的现状
🚀 科大讯飞发布讯飞星火 3.0,综合能力超越ChatGPT(非GPT-4版) 摘要:科大讯飞在2023全球1024开发者节上宣布讯飞星火 3.0正式发布,号称综合能力已超越ChatGPT。据介绍,星火认知大模型 V3.0在文…...
公网远程访问macOS本地web服务器
# 公网访问macOS本地web服务器【内网穿透】 文章目录 1. 启动Apache服务器2. 公网访问本地web服务2.1 本地安装配置cpolar2.2 创建隧道2.3 测试访问公网地址3. 配置固定二级子域名3.1 保留一个二级子域名3.2 配置二级子域名4. 测试访问公网固定二级子域名 以macOS自带的Apache…...
windows 安装小乌龟
这是什么 这里简单描述一下在windows上如何安装GIT代码管理工具和使用小乌龟版本来调用GIT,并且配置一下git相关信息,可以使用小乌龟来操作代码。也有一些常规git使用方法。 需要的资源 Git-2.42.0-64-bit.exe(这个是git代码管理工具&…...
toon boom harmony基础
以下都是tbh快捷键使用,或者一些常用功能介绍 1、在节点视图中,按回车可直接弹出节点库搜索框 2、中心线编辑器 只能编辑用笔刷画出来的线条,铅笔画出来的线条无法编辑。 3、镜头标记 1 右键箭头方向,可弹出下拉,&am…...
JPA联合主键
在实际工作中,我们会经常遇到联合主键的情况,所以我用简单例子列举JPA两种实现联合主键的方式。 1、如何通过IdClass 实现联合主键 第一步:新建一个UserInfoID类,里面是联合主键 Data Builder NoArgsConstructor AllArgsConstructor pu…...
水性杨花:揭秘CSS响应式界面设计,让内容灵活自如,犹如水之变幻
🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 ⭐ 专栏简介 📘 文章引言 一、是…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...
Easy Excel
Easy Excel 一、依赖引入二、基本使用1. 定义实体类(导入/导出共用)2. 写 Excel3. 读 Excel 三、常用注解说明(完整列表)四、进阶:自定义转换器(Converter) 其它自定义转换器没生效 Easy Excel在…...
day51 python CBAM注意力
目录 一、CBAM 模块简介 二、CBAM 模块的实现 (一)通道注意力模块 (二)空间注意力模块 (三)CBAM 模块的组合 三、CBAM 模块的特性 四、CBAM 模块在 CNN 中的应用 一、CBAM 模块简介 在之前的探索中…...
