当前位置: 首页 > 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;只不过常量的值在定义后不能进…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...