当前位置: 首页 > news >正文

JVM的基本知识

JVM

JVM是java的虚拟机,是一个十分复杂的东西,所以掌握的要求比较高.本文主要是研究JVM的三大话题

  1. JVM内存划分
  2. JVM类加载
  3. JVM的垃圾回收

JVM内存划分

java程序要执行的时候,JVM会先申请一块空间,这里就涉及到JVM的内存划分

  • 堆 : 放的是new 出来的对象
  • 栈: 放的是方法之间的调用关系(栈中可以分为虚拟机栈和本地方法栈)
    1. 虚拟机栈: java中用来保存方法调用关系的内存空间
    2. 本地方法栈: jvm中C++写的代码,算是本地的方法的调用关系的内存空间
  • 方法区: 放的是类对象(加载好的类)
  • 程序计数器: 放的是下一个要执行的指令的地址

以上的内存划分都是在java1.7的时候

代码中的局部变量: 栈上

代码中的成员变量: 堆上

代码中的静态变量: 方法区

一个JVM进程中,堆和方法区都是只有一份的,栈和程序计数器每个线程都有自己的一份

常常会结合代码来判断内存划分

image-20230225142549220

t是局部变量,所以在栈上

x是成员变量,在堆上

y是静态变量,是在类对象中,就是在方法区中

一个误区: t是一个引用类型,是不是在堆上?其实不是的!,变量在哪个部分,主要就是看变量是什么变量(局部 成员 静态)

image-20230225143116038

这里的t2 是静态的,所以实在方法区中,new 后面的 Test2是在堆上的, xx是成员变量,所以是在堆上的

JVM的类加载

类加载是什么的

java程序在 运行之前需要先编译,也就是.java --> .class二进制字节码文件

在运行的时候,JVM会读取对应的.class文件,并解析内容,在内存在构造对象并进行初始化

简单来说,类加载是将类从文件中加载到内存中

类对象描述了这个类是什么样子的,有哪些属性(属性的名字 类型 访问权限)

有哪些方法(方法名字 参数个数 类型 返回值 访问权限)

继承自那个父类,实现了哪些接口

类对象是创建实例的具体依据

类加载的步骤

类加载大致能分成3个步骤

  1. 加载
  2. 验证
  3. 准备
  4. 解析
  5. 初始化

加载: 找到.class文件,读取文件内容,并按照.class规范来解析

验证: 检查当前的.class里的内容格式是否符合要求

准备: 给类里的静态变量分配内存空间

解析: 初始化字符串常量,将符号引用替换成直接引用

所谓的符号应用就是占位符,直接引用就是内存地址

在.class文件中,会包含字符串常量,但是在类加载之前,字符串常量没有分配内存空间,得类加载之后才会有内存空间,没有内存空间也就没有字符创常量的真实地址,所以只能先使用一个占位符,等分配好内存之后再替换之前的占位符

初始化: 针对类进行初始化,初始化静态成员,并加载父类

何时触发一个类加载

使用到一个类的时候就会触发类加载(并不是程序一启动就会进行类加载,而是在使用的时候才会进行类加载) [类似于懒汉模式]

具体什么情况是使用呢?

  1. 创建这个类的实例
  2. 使用了这个类的静态属性或者静态方法
  3. 使用了类的子类(加载子类就会触发加载父类)

双亲委派模型

JVM加载类是由 类加载器 (class loader)来负责的

JVM自带了多个 类加载器的

Bootstrap ClassLoader

Extension ClassLoader

Application ClassLoader

这个三个类加载器负责不同的模块

Bootstrap ClassLoader 负责加载标准库中的类

Extension ClaaLoader 负责加载JVM拓展的库的类

Application ClassLoader 负责加载我们自己项目中的自定义类

描述上述三个类加载器如何相互配合的工作工程,就是双亲委派模型

  1. 上述的三个类加载器存在父子关系,其中Application ClassLoader是最小的子类
  2. 进行类加载时,输入的内容要是全限定类名(写完整的类名),比如: java.lang.Thread
  3. 加载的时候先从最小的子类Application ClassLoader开始,但是类加载器不会立刻扫描自己负责的路径,而是将任务委派给父 "类加载器"来处理

image-20230225162157597

image-20230225163324892

垃圾回收机制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主要的回收对象

image-20230225193453512

GC是怎么执行的

GC其实主要就是两步骤

  1. 先找出垃圾(看看谁是垃圾)
  2. 在回收垃圾(释放内存)

判定对象是不是垃圾

如果一个对象再也不会使用了,就算是垃圾了

在Java中,对象的使用,需要借助引用,要是一个对象,已经没有任何引用指向它了,说明了这个对象再也无法被使用了,就算是垃圾了

所以,判断是不是垃圾的最重要的就是,存在引用说明对象不是垃圾,要是引用不存在了就说明是垃圾

判断对象是否存在引用的两种方法是引用计数(不是JVM采用的方法,但是Python和PHP使用) 和 可达性分析(JVM中使用的方法)

所以要注意审题 : 确实问的是Java的垃圾回收机制还是"垃圾回收的机制",这里的两种方法是用来判断是不是垃圾

引用计数

给每个对象加上一个计数器,这个计数器表示当前的对象有几个引用

每当多一个引用指向该对象,计时器+1

每当少一个引用指向该对象,计数器-1(比如引用是一个局部变量,出了作用域 或者引用是一个成员变量,所在的对象被销毁了)

当计数器变成0的时候,说明此时已经没有引用指向这个对象了,所以就可以释放内存了

引用计数的优点: 简单 容易实现 执行效率也比较高

应用计数的缺点:

  1. 空间利用率地,尤其是对于小对象而言. 要是一个小对象中只有一个int的成员,结果还有拿出一个int的空间给计数器
  2. 可能会出现循环引用的情况

image-20230225200445408

这两个对象实现了循环相互调用,这样子最后计数器就是1了,但是也没有引用能指向它们,所以就不能被释放

可行性分析[JVM采用的方法]

约定一些特定的变量来作为GC roots

每个一段时间,从GC roots出发,进行遍历,看看哪些变量能被访问到,能访问到的变量就算是"可达"

这里的GC roots可以是栈上的变量 / 常量池引用的对象 / 方法区,引用类型的静态变量

image-20230225201246133

在找到 垃圾之后该怎么回收垃圾?

具体回收垃圾有4中方法

  • 标记清除
  • 复制算法
  • 标记整理
  • 分代回收

标记清除

image-20230225202546689

在发现哪些是垃圾之后,键对象对应的内存空间释放

简单粗暴,但是有一个最大的问题,就是会导致产生内存碎片,加上上图中的深色的垃圾每个占1KB,清除完之后我想要申请一个2KB的的空间都申请不到,因为此时内存都是碎片的,没有连在一起的空间

复制算法

image-20230225204242741复制算法虽然能解决内存碎片的问题,但是缺点也是很明显的

复制算法的缺点:

  • 空间利用率更低了(每次都是只用一半的内存)
  • 一轮GC下来,万一大部分对象都是要保留的,只有少部分的对象要回收,这个时候复制的开销就会很大

标记整理

保证整理的方法类似于顺序表 删除/覆盖元素 主要是搬运操作

image-20230225205202666

标记整理的空间利用率提高了,也能解决内存碎片的问题,但是搬运操作也是比较耗时的

分代回收

分代回收将上面的复制算法和标记整理综合了一下,根据 对象的不同特点来采取不同的回收方式,这里的对象特点主要是指对象的年龄

对象的年龄是根据GC的轮次来的

GC 就是一组线程,周期性扫描代码中的所有对象,要是一个对象经历了一次GC,没有被回收,它的年龄就要+1

一个基本的经验规律:

如果一个对象的寿命比较长,大概率就还会活的根据(要死早就死了,能活下来,说明生命力还比较旺盛)

针对以上的经验,将对象分成新生代(minor GC)(GC扫描的评率更高)和老年代(full GC / major GC)(GC扫描的频率更高)

image-20230225212354849

新生代(minor GC): 刚刚被创建出来的新对象,往往很容易朝生夕死,很多对象都熬不过一轮GC

新对象会进入到伊甸区,要是新对象能坚持过一轮GC, 没挂,就会通过复制算法,复制到生存区

进入到生存区之后,每熬过一次GC,就会通过复制算法拷贝到另一个拷贝去,要是这个对象能一直不消亡 , 就会在两个生存区栈反复拷贝,每次GC都会筛选掉很多的对象

要是一个对象能在生存区中坚持了很多轮GC,还不挂,则进入到老年代(full GC / major GC )

当对象来到老年代,GC也还是会有的,只是频率低很多,这里每轮GC使用的是标记整理的方式来处理老年代对象

分代回收的过程,非常像找工作的情况

总结一下:

  1. 判断垃圾
    • 引用计数
    • 可达性分析
  2. 进行回收
    • 标记清除–>内存碎片
    • 复制算法–>浪费空间大
    • 标记整理–>类似于顺序表搬运元素,时间比较长
    • 分代回收–>因地制宜完成回收

相关文章:

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沈阳站上,东北大学命题组给参赛的选手们出了一道签到题&#xff0…...

华为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组件型&#xff08;可直接用&#xff09; 组件代码&#xff1a;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、&#xffe5;a C、_12 D、$a12 E、false F、False 作业5&#xff1a; 输入数&#xff0c;判断这个数是否是质数&#xff08;要求使用函数 for循环&#xff09; 作业6&#xff1a;求50~150之间的质数是…...

linux安装influxdb-rpmyum方式

一、influxdb的安装InfluxDB简介时序数据库InfluxDB版是一款专门处理高写入和查询负载的时序数据库&#xff0c;用于存储大规模的时序数据并进行实时分析&#xff0c;包括来自DevOps监控、应用指标和IoT传感器上的数据主要特点&#xff1a;专为时间序列数据量身订造高性能数据存…...

死锁

1.死锁的定义 多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而&#xff0c;并发执行也带来了新的问题——死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局&#xff08;互相等待&#xff09;&#xff0c;若无外力作用&#xff0c;这些进程都将无法…...

C++基础了解-05-C++常量

C常量 一、C常量 常量是固定值&#xff0c;在程序执行期间不会改变。这些固定的值&#xff0c;又叫做字面量。 常量可以是任何的基本数据类型&#xff0c;可分为整型数字、浮点数字、字符、字符串和布尔值。 常量就像是常规的变量&#xff0c;只不过常量的值在定义后不能进…...

相机响应函数(CRF)的奥秘:为什么你的OpenCV计算结果每次都不一样?

相机响应函数(CRF)的稳定性挑战&#xff1a;从原理到OpenCV实战优化 每次用同样的代码计算相机响应函数(CRF)&#xff0c;结果却总是不尽相同&#xff1f;这背后隐藏着从硬件特性到算法实现的复杂交互。本文将带您深入理解CRF的本质&#xff0c;剖析OpenCV实现中的关键变量&…...

AI驱动的像素级区域划分:Krita智能选区工具提升数字创作效率全指南

AI驱动的像素级区域划分&#xff1a;Krita智能选区工具提升数字创作效率全指南 【免费下载链接】krita-vision-tools Krita plugin which adds selection tools to mask objects with a single click, or by drawing a bounding box. 项目地址: https://gitcode.com/gh_mirro…...

Kali桥接模式实战:从静态IP到动态DHCP的完整网络配置指南

1. 为什么需要桥接模式&#xff1f; 很多刚接触Kali Linux的朋友都会有这样的疑问&#xff1a;为什么虚拟机要配置桥接模式&#xff1f;简单来说&#xff0c;桥接模式让虚拟机就像一台真实存在的物理设备一样接入网络。想象一下你家里新买了一台电脑&#xff0c;插上网线就能直…...

Drawille Turtle图形编程:简单易学的终端绘图方法

Drawille Turtle图形编程&#xff1a;简单易学的终端绘图方法 【免费下载链接】drawille Pixel graphics in terminal with unicode braille characters 项目地址: https://gitcode.com/gh_mirrors/dr/drawille Drawille是一个创新的Python库&#xff0c;它使用Unicode盲…...

Ip2region终极指南:如何快速部署高性能离线IP定位系统

Ip2region终极指南&#xff1a;如何快速部署高性能离线IP定位系统 【免费下载链接】ip2region Ip2region (2.0 - xdb) 是一个离线IP地址管理与定位框架&#xff0c;能够支持数十亿级别的数据段&#xff0c;并实现十微秒级的搜索性能。它为多种编程语言提供了xdb引擎实现。 项…...

QWEN-AUDIO应用案例:如何制作一个会讲故事的AI语音玩具

QWEN-AUDIO应用案例&#xff1a;如何制作一个会讲故事的AI语音玩具 1. 项目背景与创意来源 1.1 儿童教育市场的语音需求 在当今儿童教育领域&#xff0c;互动性和趣味性成为产品设计的关键要素。传统的故事机往往只能播放预录制的音频内容&#xff0c;缺乏个性化和互动能力。…...

Qwen3-TTS-VoiceDesign参数详解:Temperature与Top P加点调优指南

Qwen3-TTS-VoiceDesign参数详解&#xff1a;Temperature与Top P加点调优指南 你是不是也遇到过这样的问题&#xff1a;用AI生成语音时&#xff0c;明明输入了“开心的语气”&#xff0c;出来的声音却平淡得像在念说明书&#xff1f;或者想要“悲伤一点”&#xff0c;结果听起来…...

南北阁Nanbeige 4.1-3B实现AIGC应用:内容生成实战案例

南北阁Nanbeige 4.1-3B实现AIGC应用&#xff1a;内容生成实战案例 1. 模型效果概览 南北阁Nanbeige 4.1-3B作为一款轻量级大语言模型&#xff0c;在AIGC内容生成领域展现出了令人惊喜的能力。虽然参数量相对较小&#xff0c;但在实际测试中&#xff0c;它在文本创作、代码生成…...

Tessent Shell双Pass插入策略深度解读:为什么MemoryBIST要先于EDT/OCC插入?

Tessent Shell双Pass插入策略&#xff1a;MemoryBIST优先于EDT/OCC的技术本质解析 在芯片测试领域&#xff0c;Tessent Shell的双Pass插入流程&#xff08;Two-Pass Insertion Process&#xff09;是一个被广泛采用却鲜少深入探讨的核心方法论。当工程师首次接触"先Memory…...

ECharts甘特图实战:5分钟搞定项目进度可视化(附完整代码)

ECharts甘特图实战&#xff1a;5分钟搞定项目进度可视化&#xff08;附完整代码&#xff09; 项目管理中&#xff0c;进度可视化是团队协作的核心需求。传统表格难以直观展示任务依赖关系&#xff0c;而专业项目管理软件又过于笨重。ECharts作为国内最流行的数据可视化库&…...