JVM 垃圾回收

news2024/11/24 19:02:04

JVM 垃圾回收

  • 如何判断哪些对象需要进行回收
    • 垃圾收集算法

Java自动内存管路主要是针对对象的内存回收和对象的内存分配,其中Java自动内存管理中最核心的就是堆内存中对象的分配和回收

如何判断哪些对象需要进行回收

1.引用计数法
给对象中添加以恶搞引用计数器

  • 每当有一个地方引用它时,计数器就加1
    • 当引用失效的时候,计数器就减1
      • 任何时候计数器为0的对象就是不可能在被使用的
        这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,最主要的原因就是它很难解决对象之间互相循环引用的问题。
        在这里插入图片描述
        像这样两个对象之间相互引用,对象的计数器都不会是0,就会造成内存泄漏。

2.可达性分析算法
这个算法的基本思想就是通过一系列的“GC Roots”的对象作为起点,从这些加点开始向下进行搜索,节点所走过的路径被称为引用链,当一个对象到“GC Roots”没有任何引用链相连的话,则证明此对象是不可用的,需要被回收。
在这里插入图片描述
哪些对象可以作为 GC Roots 呢?

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 本地方法栈(Native 方法)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 所有被同步锁持有的对象
    即使不可达,对象也不一定会被垃圾收集器回收,
    1)先判断对象是否有必要执行 finalize()方法,对象必须重写 finalize()方法且没有被运行过。
    2)若有必要执行,会把对象放到一个队列中,JVM 会开一个线程去回收它们,这是对象最后一次可以逃逸清理的机会。

3.引用
无论是通过桔树算法判断对象的引用数量,还是通过可达性分析算法判断是否引用链可达,判断对象是否存活都和“引用”离不开关系。
在JDK1.2之前,Java中引用的定义很传统:如果reference类型的数据储存的数字数值代表的是另一块内存的起始地址,就称这块内存代表一个引用。
JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用四种

  • 强引用是最传统的“引用”定义,是指程序代码中普遍存在的引用赋值,即类似Object obj = new Object() 这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收点被引用的对象
  • 软引用是用来描述一些还有用,但是非必须的对象,只要被软引用关联着的对象,在系统将要发生内存溢出的异常前,会把这些对象列入回收范围之中进行二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出的异常,在JDK1.2之后提供了SoftReference类来实现软引用。
  • 弱引用也是用来描述那些非必须对象的,但是它的强度要比软应用更低一些,被弱引用关联的对象只能生存到下一次垃圾回收发生为止,当垃圾收集器开始工作时,无论内存空间是否足够,都只会回收掉被弱引用关联的对象。在JDK1.2之后提供了WeakReference类来实现软引用。
  • 虚引用也称为“幽灵引用”或者“幻影引用”,他是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对线其生存时间造成影响,也无法通过虚引用来获得一个对象实例,为一个对象设置虚引用的唯一目的就是能够在这个对象被回收器回收时收到一个系统通知。在JDK1.2之后提供了PhantomReference类来实现软引用。
    4.回收方法区
    有些人认为方法区(如HotSpot虚拟机种的元空间或者永久代)是没有垃圾收集行为的,《Java虚拟机规范》种提到过可以不要求虚拟机在方法去中实现垃圾回收,事实上也确实为实现或者未能完整实现方法区类型卸载的收集器的存在(如JDK11时的ZGC收集器就不支持类卸载),方法区垃圾收集通常可以回收70%至99%的内存空间,相比之下,方法区回收拘于苛刻的判定条件其区域内的垃圾回收成果远低于此,
    方法区的垃圾回收主要共分为两种:废弃的常量和不再使用的类型。回收废弃常量与回收Java种的对象非常类似,举个常量池的例子,假如一个字符串“java”曾进入常量池,但是系统中没有任何一个字符串对象的值是’java“,如果此时发生内存回收,而且垃圾回收器判断确有必要的话,这个java常量就会被系统清理出常量池,常量池中的其他类、接口、方法、字段符号的引用也与此类似。
    如何判断一个类是无用的类
    方法区主要回收的是无用的类,那么如何判断一个类是无用的类的呢?

判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面 3 个条件才能算是 “无用的类” :

  • 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
  • 加载该类的 ClassLoader 已经被回收。
  • 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
  • 虚拟机可以对满足上述 3 个条件的无用类进行回收,这里说的仅仅是“可以”,而并不是和对象一样使用了就会必然被回收。

垃圾收集算法

1.分代收集理论
当前商业虚拟机的垃圾收集器,大多都遵循了分代收集的理论进行设计,分代收集名为理论,实际是一套符合大多数程序运行实际情况的经验法则,它建立在两个分代假说之上::
1)弱分代假说:绝大多数对象都是朝生夕灭的
2)强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡
这两个分代收集假说奠定了多款常用的垃圾收集器的一致的设计原则:收集器应该将Java堆划分出不同的区域,然后将回收的对象依据其年龄(即熬过垃圾收集过程的次数)分配到不同的区域之中储存,显而易见,如果一个区域中的大多数对象都是朝生夕灭,难以熬过垃圾收集的过程的话,那么九八他们集中在一起,每次回收时只关注如何保留少量存活而不是去标记那些大量的将要被回收的对象,就能以较低的代价回收到大量的空间。
2.标记清除算法
该算法分为标记和清除两部分:首先标记出所有不需要回收的对象,在标记完成后统一回收掉所有没有被标记的对象,它是最基础的收集算法,后续的算法都是对其不足进行改进得到的。这种垃圾收集算法会带来两个明显的问题:
1)效率问题
2)空间问题(标记后会产生大量不连续的碎片)
标记前
在这里插入图片描述在这里插入图片描述
如果Java队中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量的标记和清除的动作,导致标记和清除的效率都随对象数量的增长而降低。

标记删除后
碎片就是多余的白色部分,明明可以放一个很大的对象,但是因为内存空间的不连续,导致内存不够。
解决办法
1.标记整理算法
根据老年代的特点提出来的一种标记算法,标记过程仍然与”标记清除“算法一样,但是后续步骤不是直接对可回收对象进行回收,而是让所有存活的对象向一端移动,然后直接清理到边界以外的内存。
在这里插入图片描述

2.标记-复制算法
为了解决效率问题,“标记-复制”收集算法出现了。它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。

在这里插入图片描述

这种算法实现简单、运行高效,不过其缺陷也显而易见,这种复制回收算法的d代价是将可用内存缩小为了原来的一半,空间浪费很大。

3.分代收集算法
当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活的周期的不同将内存分为几块。一般将Java堆分为新生代和老年代这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
例如,在新生代中,每次收集都会有大量的对象死去,所以可以选择标记复制的算法,只需要付出少量对象的复制成本就可以完成每次的垃圾收集,而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择标记清除或者标记整理的算法吖来进行垃圾回收。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PyTorch合集2

先说一个小内存的部署 然后在说一下刚出的pytorch2.0 100%向后兼容,一行代码将训练提速76% 前段时间,PyTorch 团队在官方博客宣布 Pytorch 1.13 发布,包含 BetterTransformer 稳定版等多项更新。在体验新特性的同时,不少人也在期…

58-66-hive-数据类型-分区-分桶

58-hive-数据类型-分区: 分区表(将数据分开放,理解市区,指定分区更快,避免全数据扫描,提高查询效率,对hive的一种优化) 分区表实际是对应一个 HDFS 文件系统上的独立的文件夹&…

回归预测 | MATLAB实现基于RF随机森林的工业增加值预测(多因素、多指标)

回归预测 | MATLAB实现基于RF随机森林的工业增加值预测(多因素、多指标) 目录 回归预测 | MATLAB实现基于RF随机森林的工业增加值预测(多因素、多指标)预测效果基本介绍程序设计拓展学习参考资料预测效果 基本介绍<

Raspberry Pi 4B树莓派学习笔记

这两天在学习Raspberry Pi 4B树莓派&#xff0c;这篇笔记就梳理一下目前学习到的一些知识&#xff0c;加强自己的记忆&#xff0c;整理一下思路&#xff0c;也希望能给大家带来帮助&#xff01;感兴趣的小伙伴欢迎评论区留言或者私信博主&#xff01; 目录 一、什么是树莓派 …

C/C++_IO缓存问题

平常在练习的时候&#xff0c;总是忽略IO的缓存&#xff0c;这篇笔记记录下C和C的缓存问题。 1 什么是缓存 缓存就是程序在内存中开辟的用来存放数据的空间&#xff0c;之所以叫缓存是因为这个变量时用来暂存数据用的。比如下面的语句&#xff0c; int a ; int *p malloc(…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java高考信息发布平台cnj61

最近大四学弟学妹们开始准备设计了&#xff0c;有一些问题问我&#xff0c;比如设计怎么做&#xff0c;有没有模板等等吧&#xff0c;大家都没有去学校&#xff0c;老师都是通过远程指导的&#xff0c;答辩也是远程答辩&#xff0c;这种情况下同学们不在一起&#xff0c;可能碰…

PPT素材、PPT模板免费下载

想要PPT模板、PPT素材、PPT图表、PPT教程等相关素材&#xff0c;一定要知道这几个网站&#xff0c;不仅能免费下载&#xff0c;质量还非常高&#xff0c;话不多说&#xff0c;直接上内容。1、菜鸟图库 https://www.sucai999.com/search/ppt/0_0_%E6%9E%81%E7%AE%80_0.html?vNT…

译码器的电路

译码器与编码器正好是相反的操作&#xff0c;编码器是把高低电平转换成二进制信号 译码是把二进制编码转换成高低电平输出 译码器的逻辑功能是将每一个对应的二进制编码转化成高低电平或者另一种信号&#xff0c;是编码的另一种逆向的操作&#xff0c;编码器有二进制&#xf…

【专栏】核心篇07| Redis “jio”美的集群模式

关注公众号 【离心计划】呀&#xff0c;一起逃离地球表面 Redis专栏合集 【专栏】01| Redis夜的第一章 【专栏】基础篇02| Redis 旁路缓存的价值 【专栏】基础篇03| Redis 花样的数据结构 【专栏】基础篇04| Redis 该怎么保证数据不丢失&#xff08;上&#xff09; 【专…

Tableau:详细表达式(LOD表达式)的计算过程

写在最前 很早以前写过一篇关于Tableau详细级别表达式的博客&#xff0c;具体可以参考https://blog.csdn.net/yeshang_lady/article/details/104945361。前序博客重点在于介绍三种详细级表达式&#xff0c;这篇博客主要介绍使用详细级别表达式时的注意事项。 1 LOD表达式与非聚…

毕业设计-深度学习的施工安全帽图像检测算法

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

2022 年超详细过程步骤讲解 CentOS 7 安装jdk1.8

linux系统下安装jdk以及环境变量的设置、真的是比window下方便一万倍 1、卸载系统自带jdk 1.1 查看系统自带jdk java -version1.2 查看java相关文件 rpm -qa | grep java1.3 删除openjdk相关文件 我上边有四个对应文件 命令介绍&#xff1a; rpm     管理套件 -e   …

VMware=win’server2016=Hyper-V的使用安装

VMware=win’server2016=Hyper-V的使用安装 实验准备 VMware软件--win’server2016虚拟机一台 从外部本地计算机或U盘 上传/共享 一个映像文件进虚拟机 win2016虚

【Maven】Maven快速入门2022版:从概念、安装到基本使用

本期目录一、 简介1. Maven优点2. 强大的依赖管理3. 工作原理3.1 POM3.2 Maven模型二、 安装配置1. Maven核心程序解压与配置1.1 解压1.2 指定本地仓库1.3 配置阿里云提供的镜像仓库1.4 配置Maven工程的基础JDK版本2. 配置环境变量2.1 检查 JAVA_HOME2.2 配置MAVEN_HOME三、 Ma…

9、Springboot整合Swagger3

1.什么是Swagger&#xff1f; 我们在编写了大量的接口之后&#xff0c;如果接口的调用者不是自身的话&#xff0c;那么就会面临要编写接口文档的苦恼&#xff0c;这时候Swagger就应运而生了。 Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTf…

笔试强训(四十)

目录一、选择题二、编程题2.1 发邮件2.1.1 题目2.1.2 题解一、选择题 &#xff08;1&#xff09;上网的时候&#xff0c;访问某个页面却突然出现了某个运营商的网页&#xff0c;出现此问题可能的原因是&#xff08;A&#xff09; A.DNS劫持 B.DDos攻击 C.MAC地址欺骗 D.伪造DH…

springboot+zookeepr+dubbo的远程服务调用

首先一定确保zookeeper正常工作 公共接口模块 为了简化代码&#xff0c;可以把需要其他服务调用的接口&#xff0c;抽取为公共接口模块dubbo-common-service&#xff0c; public interface TestService {public String clientTest(); }服务提供方 导入dubbo、zookeeper依赖…

Python学习基础笔记十六——函数嵌套

1、函数的嵌套调用 def max(a, b):if a > b:return aelse:return bdef the_max(x, y, z): # 函数的嵌套调用c max(x, y)return max(c, z)print(the_max(1, 2, 3)) 2、函数的嵌套定义&#xff1a; a 1def outer():a 1def inner():b 2print(a)print(Inner)def inner2(…

【GlobalMapper精品教程】033:影像地图羽化方式详解

在Globalmapper中,可以很方便的对影响进行多种羽化值设置。 文章目录 1. 不要羽化此图层2. 沿一个或多个边缘羽化3. 羽化到有效数据的多边形覆盖4. 在当前选定的多边形内羽化5. 裁剪到选定的边界,而不是羽化6. 在多边形外部羽化,而不是内部加载配套案例数据包中的data033.ra…

Java基于springboot+vue的家用电器销售购物商城系统 前后端分离

开发背景和意义 随着人们生活的改变&#xff0c;家电基本在家家户户都存在&#xff0c;常用的家电例如冰箱&#xff0c;洗衣机&#xff0c;电视机&#xff0c;空调等设备可以让人们的生活方式变的更加快捷舒适&#xff0c;通常情况下人们购买家电的话都是到指定的家电销售场所…