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常量 常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。 常量可以是任何的基本数据类型,可分为整型数字、浮点数字、字符、字符串和布尔值。 常量就像是常规的变量,只不过常量的值在定义后不能进…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器: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. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 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数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...