JVM的垃圾回收

JVM简介

JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机。
虚拟机:是指通过软件模拟的具有完整硬件功能、运行在一个完全隔离的环境中完整计算机系统

1.JVM的内存区域划分
jvm是一个java进程 每一个java进程就是一个jvm实例
一个进程运行过程中 就要从操作系统这里申请到一些内存资源 jvm也是如此 所以用一块内存供java代码执行时使用 jvm把这一块内存 有划分几个区域作为不同的用途
在这里插入图片描述
栈里面方法的调用关系 局部变量(使用的是递归调用)
栈空间和程序计数器 是每一个线程各有一份
每个线程 都是一个独立的执行逻辑 就能得到单独记录执行到哪里

下面有一段代码

class Test{
	public int n = 20;
	public static int a = 10;
}
public static void main(){
	Test t = new Test();
}

n是普通的成员变量 就是包含在new对象内部 堆上的
a是一个静态成员变量 是包含在类对象中方法区的
t是一个局部变量(引用类型) 栈上
这里栈上的t保存了堆上new Test()的内存地址

2.JVM类加载机制
把类从硬盘加载到内存中 java程序最开始就是写一个java文件编译成.class文件(字节码) 运行java程序JVM就会读取class文件 把文件内容 放到内存中并构成class对象

简单描述下类加载

  1. 加载找到class文件 打开文件 读取文件内容并尝试解析格式
    在java代码就是直接使用类
  2. 验证 检查当前.class文件格式 是否符合要求
    ,这一阶段的目的是确保Class文件的字节 流中包含的信息符合《Java虚拟机
    规范》的全部约束要求,保证这些信 息被当作代码运行后不会危害虚拟机自身的安全。
  3. 准备 给类对象分配内存
    最终目的是构造出完整的类对象 分配内存+初始化
    分配出来的内存空间 内容就是权威0的值(此时此刻 类对象上static成员也就是都是0)
  4. 解析 主要是初始化类对象中涉及到的一些字符串常量
  5. 初始化对类对象进行更具体的初始化操作初始化静态成员 执行静态代码块 加载父类

双亲委派模型(描述类加载过程中 如何找到.class文件)
JVM加载.class文件的时候需要用到"类加载器"模块
JVM中自带了三个类加载器
Bootstrap ClassLoader 负责加载标准库中的类
Extension ClassLoader 负责加载JVM扩展的库
Application ClassLoader 负责加载第三方库(mysql jdbc driver servlet jackson 等)

  1. 从Application ClassLoader开始
    不会立即就搜索第三方库的目录 而是先把加载任务委派给父亲 让父亲先尝试加载
  2. 到了Extension ClassLoader
    也不会立即搜索扩展库的目录 而是继续把任务派给父亲 让父亲先尝试加载
    3)再到Booststrap ClassLoader
    同样不会立即搜寻标准库 但是Bootstrap ClassLoadr没有父亲了就只能自己搜索 如果没找到这个类就会交给孩子完成 -> Extension ClassLoader
  3. 任务回到Extension ClassLoader
    如果找到了这个类 就进行后续加载
    如果没找到这个类就会交给孩子完成
    5)任务回到Application ClassLoader
    如果找到了类就进行后续加载
    如果没找到就会抛出一个异常

双亲委派模型 工作就是找.class文件 每个类加载器都有自己的"父亲"

一个类什么时候才会被加载?
类的加载使用的是懒汉模式 用到了才加载
分为以下三种情况

  1. 构造类的实例
  2. 使用了类的静态方法/静态属性
  3. 子类的加载会触发父类
    类加载之后 后续就不用加载了

类卸载 类的卸载
一般来说类卸载是属于特殊情况
类加载之后就不会考虑卸载 一直保持到程序运行结束
但有时我们服务器需要打 热补丁 需要卸载操作

3.JVM的垃圾回收机制(GC)
java的垃圾回收机制 会自动判定 某个内存是否会继续使用(如果不会 就会把内存当初垃圾 自动把垃圾释放掉)

垃圾回收 对于java来说 回收的是对象而不是字节(GC不是判定某个字节是不是垃圾而是判定对象是不是垃圾 进一步去进行回收的)

JVM中有几个内存区域 GC回收是回收的是那里的对象?
JVM的内存区域有栈 堆 方法区 栈空间不需要GC回收栈里面包含很多"栈帧"每一个栈帧对应一个方法 该方法执行结束 此时这个栈帧就销毁了 然后在栈上的局部变量就自然销毁了

程序计数器同理 线程销毁 也自然跟着销毁

方法区 类对象 很少会涉及对象的卸载

所以 堆 GC的主要战场

Java垃圾回收 分两步

  1. 判定对象是否是"垃圾"
    如果一个对象 在后续代码中不再被使用就可以看作是垃圾了 一个对象如果没有任何引用指用它就可以认为是垃圾(Java中要使用一个对象 只有一种途径 就是先创一个引用指向它 然后通过引用访问对象的属性/方法)
    例如:
public void test(){
	T t = new T();
	t.function();
}
test();

t是一个局部变量此时 test方法执行完毕之后 t 就自然销毁 此时 new T() 对象就没有引用了 此时 这个对象就是垃圾

判定对象是否是垃圾 就是看这个对象是否有引用指向它 那么如何看对象是否有引用指向它呢?

思路一: 引用计数
给这个对象里面安排一个计数器 每次有引用指向它 就把计数器加一 每次引用被销毁 计数器减一 当计数器为0 的时候就说明这个对象是垃圾了
例如:

class Test{
	int m;
	int n;
}
Test a = new Test();
Test b = a;
Test c = b;

对象中 会专门留一个空间来存储引用的个数
在这里插入图片描述

此处a这个引用指向Test
b指向引用a
c指向引用b
然后Test的就被引用了三次 所以计数器加三
在这里插入图片描述
然后我们将
a = null;
此时引用减少一次 计数器减一
在这里插入图片描述
当剩下两个引用都置为null时 这个对象就是垃圾了
在这里插入图片描述
这就是引用计数方案 但存在两个明显的缺陷

  1. 空间利用率比较低 浪费更多的内存空间
    如果给引用计数分配了2各字节 对象本体才4各字节 引用计数就浪费了50%的空间 代码中都是小对象 并且数量多时浪费就很明显了
  2. 可能存在循环引用的问题 且对象不能被正确识别为垃圾
    例如:
class Test{
	public Test t;
}
//第一步
Test a = new Test();
Test b = new Test();
//第二步
a.t = b;
b.t = a;
//第三步
a = null;
b = null;

第一步时
在这里插入图片描述

第二步时
在这里插入图片描述
第三步时
在这里插入图片描述
此时这两个对象计算器不为0 不能被当作垃圾 于此同时 想要使用对象1 就要访问 对象2 想使用对象2就要访问道对象1 谁都用不了 谁有无法释放和死锁非常相似

方案二: 可达性分析 (这是java中实际采取的方式)
JVM 首先会从现有代码中能直接访问到的引用出发尝试遍历所有能访问的对象 只要对象能访问到就会标记成可达 完成所有遍历之后 不能访问到的对象就是不可达 就相当于垃圾了

gc root(从那些对象开始出发扫描?)

  1. 栈上的局部变量
  2. 常量池的引用
  3. 方法区中的静态成员

例如:

在这里插入图片描述
这样一颗二叉树结构
root = a
root.left = b
root.left.left = d
以此类推可以通过a进行访问到后续任何一个节点
如果此时令root.left.left = null 此时d就会空无法通过root遍历d就是不可达得了 此时d引用的对象就会被垃圾回收

以上就是可达性分析 和引用计数不同的时它消耗的是时间 通过引用计数可以非常快的知道对象是否是垃圾但是会消耗大量的空间
而可达性分析不会引入额外的空间开销 但进行遍历需要消耗时间

可达性分析的扫描是持续的 周期性的

  1. 释放对象的内存
    那我们确定了垃圾 又该如何清理垃圾 释放对象呢?

(1) 标记清除
直接释放对象 但是可能引起内存碎片
在这里插入图片描述
这是因为申请内存的时候都是申请连续的内存空间
释放内存就可能会破坏原有的连续性 导致内存申请不了 如果不处理内存碎片会随着程序的运行越来越多 越来越碎内存就会变得很难申请了

(2) 复制算法
复制算法 通过冗余的空间 把有效对象复制到另一个部分空间 避免内存碎片

把一个内存 分成两份用一份 删除一份
把左侧区域中有效的对象复制到右侧
使用右侧区域使用一段时间后存在很多对象然后把有效的对象在复制到左侧然后把左侧的对象全部同意释放
例如:
假设对象2是垃圾对象然后把13复制到右边内存再释放掉左侧内存

在这里插入图片描述
在这里插入图片描述
这里如果复制的内容多 内存开销很大内存率不高

(3) 标记整理
顺序表删除元素
假设34是

在这里插入图片描述
把5对象往前移两个单位内存就相当于删除了

在这里插入图片描述
这一方法解决了内存利用率低的问题但是
搬运的元素成本比较高

(4) 分代回收
Java代码中 对象分成两个大类
1.生命周期特别长
2.生命周期特别短
所以可以按照对象的年龄来定制不同的回收策略
GC就是周期性扫描 一个对象每经历一轮GC就看作长了一岁
在这里插入图片描述

新生的对象就在伊甸区 这里的对象大部分无法活过第一轮GC 第一轮gc经过之后还剩下的对象 就会被通过复制算法复制到幸存区

幸存区继续使用复制算法 如果这个对象在幸存区经过了许多轮依旧没有清理掉 就进入了老年代了

新生代的扫描频率比较高
老年代的扫描频率比较低

新生代每一轮gc留下的有效对象不过 使用复制算法开销不大
老年代不会有频繁的对象销毁对此 使用标记整理开销不大

还有一个特殊情况如果对象体积特别大就会直接进入老年代

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/606156.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uniapp0基础编写安卓原生插件之编写安卓页面在uniapp上显示(摄像头调用)

前言 如果你对安卓插件开发部分不熟悉你可以先看uniapp0基础编写安卓原生插件和调用第三方jar包和编写语音播报插件之零基础编写安卓插件 效果 开始 dcloud_uniplugins.json {"nativePlugins": [{"hooksClass": "","plugins": [{&…

软件试运行方案,试运行报告(word原件获取)

一、 试运行目的 (一) 系统功能、性能与稳定性考核 (二) 系统在各种环境和工况条件下的工作稳定性和可靠性 (三) 检验系统实际应用效果和应用功能的完善 (四) 健全系统运行管理体制&…

Pspice for TI学习

Pspice for TI中PSpice Part Search空白解决方法 配置环境变量 Cad_PSpice_TI_Regr_Srvr https://software-dl.ti.com/pspice/S009 重新安装2023版的Pspice Pspice安装链接 打开新安装的软件即可发现PSpice Part Search可以正常使用了 VSIN各参赛的含义 VOFF直流偏置VAMPL…

JavaEE企业级开发中常用的Stream流

介绍 在Java编程中,Stream流是Java 8引入的一个重要概念,它提供了一种新的处理集合的方式,可以更加简洁、高效地进行数据操作。Stream流支持各种常见的操作,比如过滤、映射、排序、聚合等,同时也支持并行处理&#xf…

Vue 项目 尚品汇(二)(暂停进行)

一、Home 模块组件拆分 基本流程 先写静态页面 拆分静态组件 获取服务器的数据进行展示 动态业务 (一)三级联动组件 如果一个组件在很多模块之间都在使用,我们就拆分成成一个全局组件 只需注册一次 在全局的项目都能使用 三级联动在 …

Java:就业市场上的常青树-永远的宠儿

除了兴趣,我们学习编程最主要的目标是找一份好工作,选择合适的编程语言就非常重要了,毕竟选择大于努力,男怕选错行,学编程最怕选错语言。比如,如果你选Perl,那就糟糕了,基本上可以断…

高效备战!2024年陕西省绿色工厂申报条件好处和各地区奖补

什么是绿色工厂? 绿色工厂是制造业的生产单元,是绿色制造的实施主体,属于绿色制造体系的核心支撑单元,侧重于生产过程的绿色化。 通过采用绿色建筑技术建设、改造厂房,预留可再生能源应用场所和设计负荷,…

PyQt5中的事件与信号处理

文章目录 1. 简介1.1事件(Event)1.2 信号(Signal)与槽(Slot)1.3 自定义信号 2. 一个信号与槽的简单示例13. 一个信号与槽的简单示例24. 事件发送者5. 创建自定义信号6. 一个简单计算器 1. 简介 在PyQt5中,事件和信号处理是GUI编程的核心概念。事件是指用户操作或系…

吴恩达机器学习笔记:第 9 周-16推荐系统(Recommender Systems) 16.3-16.4

目录 第 9 周 16、 推荐系统(Recommender Systems)16.3 协同过滤16.4 协同过滤算法 第 9 周 16、 推荐系统(Recommender Systems) 16.3 协同过滤 在之前的基于内容的推荐系统中,对于每一部电影,我们都掌握了可用的特征,使用这些特征训练出了…

codeforce#937 (div4)题解

E. Nearly Shortest Repeating Substring 给出字符串s,是否存在长度为k的字符串多次拼接后得到的字符串与s最多有一位不同 由题意得,k一定是n的因数,所以暴力枚举就好,求出满足 s [ i ] s [ i m o d k ] s[i] s[i \mod k] s[…

C++之初阶模板

个人主页:救赎小恶魔 欢迎大家来到小恶魔频道 好久不见,甚是想念 今天我们要深入讲述C内存管理 目录 引言: 模板 1. 泛型编程 2. 模板函数 2.1函数模板的原理 2.2模板函数的实例化 2.3函数模板的匹配 3.类模板 STL STL 的主要组…

[答疑]关于《评“状态和事件本质相同”》的6个疑问

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 丁绍恒 2024-5-8 16:17 (补注:上图摘自https://mp.weixin.qq.com/s/QhAhSdET5psZQEEW6f9KoA) 1、您提到“【警戒条件】是一个【表达式】&#xff0…

内网安全综合管理系统是什么 | 好用的那我王安全管理系统有哪些

内网安全综合管理系统是指一种集成终端管理、网络管理、内容管理、资产管理等功能的综合性安全管理系统。它主要对内网上的主机进行统一安全管理,包括对网络主机用户操作实施监督控制,并对主机中的安全软件(如主机入侵监测系统、主机防火墙和…

【编程基础】人人都应该懂得递归小知识

文章目录 什么是递归递归和栈尾递归递归和分治归并排序 递归和 什么是递归 下面引用刘汝佳的《算法竞赛入门经典》中对递归的定义: 递归:参见递归。递归:如果你还不理解递归是什么,请参见递归。 递归事实上就是函数直接或间接调…

520送男士内裤给男朋友好吗?五大男士内裤测评种草

相信有很多朋友都选在520这个特殊的日子里为心爱的人挑选一份特别的礼物吧!如果送礼给男朋友或老公,一份实用的礼物肯定是最佳选择哦!很多男性朋友每条内裤都穿很久,如果给男朋友挑选合适的男士内裤,也是一种关心体贴的…

冯喜运:5.9今日黄金原油最新走势分及盘面操作策略布局

【黄金消息面分析】:周四(5月9日)亚市早盘,现货黄金窄幅震荡,目前交投于2313美元/盎司附近。金价周三持稳,投资者等待美国数据为美联储可能降息提供线索,地缘局势给金价提供支撑,但美…

利用爬虫解决数据采集难题

文章目录 安装为什么选择 BeautifulSoup 和 requests?安装 BeautifulSoup 和 requests解决安装问题 示例总结 在现代信息时代,数据是企业决策和发展的关键。然而,许多有用的数据分散在网络上,且以各种格式和结构存在,因…

2024年小程序视频怎么下载下来

小程序视频下载工具我已经打包好了,有需要的自己下载 小程序下载工具打包链接:百度网盘 请输入提取码 提取码:1234 --来自百度网盘超级会员V10的分享 1.首先解压好我给大家准备好的压缩包 2.退出微信,电脑右下角进行右键退出…

自适应调节Q和R的自适应UKF(AUKF_QR)的MATLAB程序

简述 基于三维模型的UKF,设计一段时间的输入状态误差较大,此时通过对比预测的状态值与观测值的残差,在相应的情况下自适应调节系统协方差Q和观测协方差R,构成自适应无迹卡尔曼滤波(AUKF),与传统…

C语言实战项目---通讯录

项目要实现的内容:能够存放100个人的通讯录程序,能够实现联系人数据的存储,删除,修改,查找,展示联系人的信息。 所需知识:结构体,指针,函数................. 废话不多…
最新文章