JVM的基本知识
JVM
JVM是java的虚拟机,是一个十分复杂的东西,所以掌握的要求比较高.本文主要是研究JVM的三大话题
- JVM内存划分
- JVM类加载
- JVM的垃圾回收
JVM内存划分
java程序要执行的时候,JVM会先申请一块空间,这里就涉及到JVM的内存划分
- 堆 : 放的是new 出来的对象
- 栈: 放的是方法之间的调用关系(栈中可以分为虚拟机栈和本地方法栈)
- 虚拟机栈: java中用来保存方法调用关系的内存空间
- 本地方法栈: jvm中C++写的代码,算是本地的方法的调用关系的内存空间
- 方法区: 放的是类对象(加载好的类)
- 程序计数器: 放的是下一个要执行的指令的地址
以上的内存划分都是在java1.7的时候
代码中的局部变量: 栈上
代码中的成员变量: 堆上
代码中的静态变量: 方法区
一个JVM进程中,堆和方法区都是只有一份的,栈和程序计数器每个线程都有自己的一份
常常会结合代码来判断内存划分

t是局部变量,所以在栈上
x是成员变量,在堆上
y是静态变量,是在类对象中,就是在方法区中
一个误区: t是一个引用类型,是不是在堆上?其实不是的!,变量在哪个部分,主要就是看变量是什么变量(局部 成员 静态)

这里的t2 是静态的,所以实在方法区中,new 后面的 Test2是在堆上的, xx是成员变量,所以是在堆上的
JVM的类加载
类加载是什么的
java程序在 运行之前需要先编译,也就是.java --> .class二进制字节码文件
在运行的时候,JVM会读取对应的.class文件,并解析内容,在内存在构造对象并进行初始化
简单来说,类加载是将类从文件中加载到内存中
类对象描述了这个类是什么样子的,有哪些属性(属性的名字 类型 访问权限)
有哪些方法(方法名字 参数个数 类型 返回值 访问权限)
继承自那个父类,实现了哪些接口
类对象是创建实例的具体依据
类加载的步骤
类加载大致能分成3个步骤
- 加载
- 验证
- 准备
- 解析
- 初始化
加载: 找到.class文件,读取文件内容,并按照.class规范来解析
验证: 检查当前的.class里的内容格式是否符合要求
准备: 给类里的静态变量分配内存空间
解析: 初始化字符串常量,将符号引用替换成直接引用
所谓的符号应用就是占位符,直接引用就是内存地址
在.class文件中,会包含字符串常量,但是在类加载之前,字符串常量没有分配内存空间,得类加载之后才会有内存空间,没有内存空间也就没有字符创常量的真实地址,所以只能先使用一个占位符,等分配好内存之后再替换之前的占位符
初始化: 针对类进行初始化,初始化静态成员,并加载父类
何时触发一个类加载
使用到一个类的时候就会触发类加载(并不是程序一启动就会进行类加载,而是在使用的时候才会进行类加载) [类似于懒汉模式]
具体什么情况是使用呢?
- 创建这个类的实例
- 使用了这个类的静态属性或者静态方法
- 使用了类的子类(加载子类就会触发加载父类)
双亲委派模型
JVM加载类是由 类加载器 (class loader)来负责的
JVM自带了多个 类加载器的
Bootstrap ClassLoader
Extension ClassLoader
Application ClassLoader
这个三个类加载器负责不同的模块
Bootstrap ClassLoader 负责加载标准库中的类
Extension ClaaLoader 负责加载JVM拓展的库的类
Application ClassLoader 负责加载我们自己项目中的自定义类
描述上述三个类加载器如何相互配合的工作工程,就是双亲委派模型
- 上述的三个类加载器存在父子关系,其中Application ClassLoader是最小的子类
- 进行类加载时,输入的内容要是全限定类名(写完整的类名),比如: java.lang.Thread
- 加载的时候先从最小的子类Application ClassLoader开始,但是类加载器不会立刻扫描自己负责的路径,而是将任务委派给父 "类加载器"来处理


垃圾回收机制GC
GC是什么
在学习C语言的时候,创建内存有两种方式
直接定义变量,变量对应着内存空间,一旦出了作用域,就会释放
还有一种是malloc申请内存(动态内存申请),务必需要通过free来释放资源,要是真的忘了就会导致内存泄漏,十分危险
所以手动释放内存是很容易出事的
GC(垃圾回收机制)是一种主流的解决方案,在Java Python JS Go PHP中都存在GC垃圾回收机制
所谓的GC: 程序员只要负责申请内存,释放内存的工作直接交给JVM完成就行了
虽然GC很好用,但是GC也有问题,其中最大的问题就是GC会引入额外的开销(时间 + 空间)
时间上会存在STW问题(Stop The World),会导致卡顿
空间上会消耗额外的CPU和内存资源
GC回收哪部分
JVM的几个部分:
方法区: 类对象, 加载之后不太会卸载
栈: 出了作用域就会释放,所以不用回收
程序计数器: 固定的内存空间,不必回收
堆: GC主要的回收对象

GC是怎么执行的
GC其实主要就是两步骤
- 先找出垃圾(看看谁是垃圾)
- 在回收垃圾(释放内存)
判定对象是不是垃圾
如果一个对象再也不会使用了,就算是垃圾了
在Java中,对象的使用,需要借助引用,要是一个对象,已经没有任何引用指向它了,说明了这个对象再也无法被使用了,就算是垃圾了
所以,判断是不是垃圾的最重要的就是,存在引用说明对象不是垃圾,要是引用不存在了就说明是垃圾
判断对象是否存在引用的两种方法是引用计数(不是JVM采用的方法,但是Python和PHP使用) 和 可达性分析(JVM中使用的方法)
所以要注意审题 : 确实问的是Java的垃圾回收机制还是"垃圾回收的机制",这里的两种方法是用来判断是不是垃圾
引用计数
给每个对象加上一个计数器,这个计数器表示当前的对象有几个引用
每当多一个引用指向该对象,计时器+1
每当少一个引用指向该对象,计数器-1(比如引用是一个局部变量,出了作用域 或者引用是一个成员变量,所在的对象被销毁了)
当计数器变成0的时候,说明此时已经没有引用指向这个对象了,所以就可以释放内存了
引用计数的优点: 简单 容易实现 执行效率也比较高
应用计数的缺点:
- 空间利用率地,尤其是对于小对象而言. 要是一个小对象中只有一个int的成员,结果还有拿出一个int的空间给计数器
- 可能会出现循环引用的情况

这两个对象实现了循环相互调用,这样子最后计数器就是1了,但是也没有引用能指向它们,所以就不能被释放
可行性分析[JVM采用的方法]
约定一些特定的变量来作为GC roots
每个一段时间,从GC roots出发,进行遍历,看看哪些变量能被访问到,能访问到的变量就算是"可达"
这里的GC roots可以是栈上的变量 / 常量池引用的对象 / 方法区,引用类型的静态变量

在找到 垃圾之后该怎么回收垃圾?
具体回收垃圾有4中方法
- 标记清除
- 复制算法
- 标记整理
- 分代回收
标记清除

在发现哪些是垃圾之后,键对象对应的内存空间释放
简单粗暴,但是有一个最大的问题,就是会导致产生内存碎片,加上上图中的深色的垃圾每个占1KB,清除完之后我想要申请一个2KB的的空间都申请不到,因为此时内存都是碎片的,没有连在一起的空间
复制算法
复制算法虽然能解决内存碎片的问题,但是缺点也是很明显的
复制算法的缺点:
- 空间利用率更低了(每次都是只用一半的内存)
- 一轮GC下来,万一大部分对象都是要保留的,只有少部分的对象要回收,这个时候复制的开销就会很大
标记整理
保证整理的方法类似于顺序表 删除/覆盖元素 主要是搬运操作

标记整理的空间利用率提高了,也能解决内存碎片的问题,但是搬运操作也是比较耗时的
分代回收
分代回收将上面的复制算法和标记整理综合了一下,根据 对象的不同特点来采取不同的回收方式,这里的对象特点主要是指对象的年龄
对象的年龄是根据GC的轮次来的
GC 就是一组线程,周期性扫描代码中的所有对象,要是一个对象经历了一次GC,没有被回收,它的年龄就要+1
一个基本的经验规律:
如果一个对象的寿命比较长,大概率就还会活的根据(要死早就死了,能活下来,说明生命力还比较旺盛)
针对以上的经验,将对象分成新生代(minor GC)(GC扫描的评率更高)和老年代(full GC / major GC)(GC扫描的频率更高)

新生代(minor GC): 刚刚被创建出来的新对象,往往很容易朝生夕死,很多对象都熬不过一轮GC
新对象会进入到伊甸区,要是新对象能坚持过一轮GC, 没挂,就会通过复制算法,复制到生存区
进入到生存区之后,每熬过一次GC,就会通过复制算法拷贝到另一个拷贝去,要是这个对象能一直不消亡 , 就会在两个生存区栈反复拷贝,每次GC都会筛选掉很多的对象
要是一个对象能在生存区中坚持了很多轮GC,还不挂,则进入到老年代(full GC / major GC )
当对象来到老年代,GC也还是会有的,只是频率低很多,这里每轮GC使用的是标记整理的方式来处理老年代对象
分代回收的过程,非常像找工作的情况
总结一下:
- 判断垃圾
- 引用计数
- 可达性分析
- 进行回收
- 标记清除–>内存碎片
- 复制算法–>浪费空间大
- 标记整理–>类似于顺序表搬运元素,时间比较长
- 分代回收–>因地制宜完成回收
相关文章:
JVM的基本知识
JVM JVM是java的虚拟机,是一个十分复杂的东西,所以掌握的要求比较高.本文主要是研究JVM的三大话题 JVM内存划分JVM类加载JVM的垃圾回收 JVM内存划分 java程序要执行的时候,JVM会先申请一块空间,这里就涉及到JVM的内存划分 堆 : 放的是new 出来的对象栈: 放的是方法之间的调…...
STM32移植FreeRTOS操作系统
一、FreeRTOS源码下载(1)移植钱得准备前菜对吧,我们先来去官网瞄一瞄网址:https://freertos.org/zh-cn-cmn-s/ 第一步:点击下载FreeRTOS第二步:选择版本下载(我选择稳定版本)注&…...
【专项训练】泛型递归、树的递归
递归和循环没有明显的边界! 不要进行人肉递归! 找最近重复子问题,直接写递归! 数学归纳法思维:1,2,…… 70. 爬楼梯 https://leetcode.cn/problems/climbing-stairs/ 互斥,且加在一起是全部答案! 动态规划法:用数组做递推,就是动态规划!!! class Solution...
React18 setState是同步还是异步?
相信大家对于react的setState肯定是不陌生了, 这是一个用于更新状态的函数. 但是在之前有一道非常经典的面试题就是关于setState是同步还是异步的问题, 具体可以参考我之前写的一篇文章: 一篇文章彻底理解setState是同步还是异步!. 对于react 18之前的版本, 上文说的…...
Kafka消费者 TCP管理
Kafka消费者 TCP管理创建 TCPFindCoordinator连接协调者消费数据TCP 连接数关闭 TCP 连接消费者的程序入口类是 KafkaConsumer 构建 KafkaConsumer 时 ,不会创建任何 TCP 连接TCP 连接是用 KafkaConsumer.poll 创建 创建 TCP poll 创建 TCP 的地方 : 发起 FindC…...
软考高级备考哪一个类型好些?
软考高级是比中级和初级难,科目就要考三科,选择题基础知识简答题案例分析写作论文 软考高级科目有:信息系统项目管理师、系统分析师、系统架构设计师、网络规划师、系统规划与管理师。如下: 软考高级中高项信息系统项目管理师师比…...
2023 HBU 天梯赛第一次测试 题目集
目录 1 建校日期 2 发射小球 3 背上书包去旅行 4 吉利的数字 5 向前走 6 热水器 7 走方格 8 朋友圈 9 交保护费 10 走方格 11 和与积 12 缩短字符串 13 买木棒 1 建校日期 在2022 ICPC沈阳站上,东北大学命题组给参赛的选手们出了一道签到题࿰…...
华为OD机试题,用 Java 解【子序列长度】问题
华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…...
内网环境解决SSL证书问题
本来这个没什么好写的,但是坑实在有点多,不得不写个文章记录下来。 创建证书看这里!!! 很多知识点要结合这个页面内容来看。 创建证书已经看过相关文章,然后用unity跑的时候发现连不上,完全没…...
数据分析方法01对比分析法
对比分析法 1、概念 基于相同的数据标准下,把两个及以上相互联系的指标数据进行比较,准确量化的分析他们的差异,说明研究对象在规模大小,水平高低,速度快慢等的不同表现,目的是为了找到差异的原因&#x…...
基于SMOKE多模式排放清单处理技术及EDGAR/MEIC清单制作与VOCs排放量核算
查看原文>>>基于SMOKE多模式排放清单处理技术及EDGAR/MEIC清单制作与VOCs排放量核算 (qq.com)随着我国经济快速发展,我国面临着日益严重的大气污染问题。近年来,严重的大气污染问题已经明显影响国计民生,引起政府、学界和人们越来越…...
CSS流动布局-页面自适应
项目中经常会碰到页面自适应的问题,例如:商城的列表展示、分类列表展示等页面,如下: 该页面会随着页面的放大缩小而随之发生变化,这种自适应的页面布局在大屏幕、小屏幕、不同的浏览器设备上都应该呈现出与设计匹配的…...
3.Elasticsearch初步进阶
3.Elasticsearch初步进阶[toc]1.文档批量操作批量获取文档数据批量获取文档数据是通过_mget的API来实现的在URL中不指定index和type请求方式:GET请求地址:_mget功能说明:可以通过ID批量获取不同index和type的数据请求参数docs:文档数组参数_index:指定index_type:指定type_id:指…...
优思学院|六西格玛管理的核心理念是什么?
六西格玛管理是一种基于数据分析的质量管理方法,旨在通过降低过程的变异性来达到质量稳定和优化的目的。该方法以希腊字母“σ”为名,代表标准差,是衡量过程变异性的重要指标。 六西格玛管理的核心理念是“以客户为中心、以数据为基础、追求…...
第十七节 多态
多态 什么是多态? ●同类型的对象,执行同一个行为,会表现出不同的行为特征。 多态的常见形式 父类类型 对象名称new子类构造器; 接口 对象名称new 实现类构造器; 多态中成员访问特点 ●方法调用:编译看左边,运行看右边。 ●变量调用:编译看…...
[vue]提供一种网站底部备案号样式代码
演示 vue组件型(可直接用) 组件代码:copyright-icp.vue <template><div class"icp">{{© ${year} ${author} }}<a href"http://beian.miit.gov.cn/" target"_blank">{{ record }}</a…...
python第四天作业~函数练习
目录 作业4、判断以下哪些不能作为标识符 A、a B、¥a C、_12 D、$a12 E、false F、False 作业5: 输入数,判断这个数是否是质数(要求使用函数 for循环) 作业6:求50~150之间的质数是…...
linux安装influxdb-rpmyum方式
一、influxdb的安装InfluxDB简介时序数据库InfluxDB版是一款专门处理高写入和查询负载的时序数据库,用于存储大规模的时序数据并进行实时分析,包括来自DevOps监控、应用指标和IoT传感器上的数据主要特点:专为时间序列数据量身订造高性能数据存…...
死锁
1.死锁的定义 多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而,并发执行也带来了新的问题——死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法…...
C++基础了解-05-C++常量
C常量 一、C常量 常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。 常量可以是任何的基本数据类型,可分为整型数字、浮点数字、字符、字符串和布尔值。 常量就像是常规的变量,只不过常量的值在定义后不能进…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
