垃圾收集算法

1.如何判断对象是否存活?

1.1引用计数算法

基本思路:

  • 在对象中添加一个引用计数器
  • 每当有一个地方引用它的时候,计数器就加+1
  • 每当有一个引用失效的时候,计数器就减-1
  • 当计数器的值为0的时候,那么该对象就是可被GC回收的垃圾对象

存在的问题:对象循环引用

a 对象引用了 b 对象,b 对象也引用了 a 对象,ab 对象却没有再被其他对象所引用了,其实正常来说这两个对象已经是垃圾了,因为没有其他对象在使用了,但是计数器内的数值却不是 0,所以引用计数算法就无法回收它们。

1.2. 可达性分析算法

又称为根可达性算法

基本思路:

过定义了一系列称为“GC Roots”的根对象作为起始节点集,从 GC Roots 开始,根据引用关系往下进行搜索,查找的路径我们把它称为 "引用链" 。当一个对象到 GC Roots之间没有任何引用链相连时(对象与GC Roots之间不可达),那么该对象就是可被GC回收的垃圾对象

可达性分析算法也是JVM 默认使用的寻找垃圾算法。

例如:

Object 6Object 7Object 8彼此之前有引用关系,但是没有与"GC Roots"相连,那么就会被当做垃圾所回收。

2.Java 中的四种引用类型

 无论上述哪种算法,我们都可以看到引用在其中的重要作用。

2.1.强引用(Strong Reference)

强引用是使用最普遍的引用。如果一个对象具有强引用,垃圾回收器绝不会回收它。当内存空间不足时,JVM 即使抛出OOM错误,使程序异常终止,也不会随意回收具有强引用对象来解决内存不足的问题。

Object strongReference = new Object();

如果强引用对象不使用时,需要弱化从而使GC能够回收。

弱化方式1

显式地设置strongReference对象为nullgc认为该对象不存在引用,这时就可以回收这个对象。

注意:具体什么时候收集取决于GC算法, 例如,strongReference全局变量时,就需要在不用这个对象时赋值为null,因为强引用不会被垃圾回收。

strongReference = null;

弱化方式2:

让对象超出作用域范围。在一个方法的内部有一个强引用,这个引用保存在VM Stack中(GC Root),而真正的引用对象(Object)保存在中。当这个方法运行完成后,就会退出方法栈,则这个对象会被回收。

public void test() {
    Object strongReference = new Object();
    // 省略其他操作
}

2.2. 软引用(Soft Reference)

如果一个对象只具有软引用,则内存空间充足时,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。所以,软引用可用来实现内存敏感的高速缓存。

// 软引用
String str = new String("abc");
SoftReference<String> softReference = new SoftReference<String>(str);

// 访问软引用
softReference.get();

 当内存不足时,JVM首先将软引用中的对象引用置为null,然后通知垃圾回收器进行回收:

public class Demo01 {public static void main(String[] args) {//强引用String strongReference = new String("abc");String str = new String("just do do");//弱引用,进行保护,内存充足不回收。SoftReference<String> softReference = new SoftReference<>(str);str = null;// Notify GCSystem.gc();try {byte[] buff1 = new byte[900000000]; // 内存充沛
//            byte[] buff2 = new byte[900000000];
//            byte[] buff3 = new byte[900000000];
//            byte[] buff4 = new byte[900000000]; // 内存不足} catch (Error e) {e.printStackTrace();}System.out.println(strongReference);System.out.println(softReference.get()); // just do do 或 null}
}

内存充足:

内存不足:

 上述案例可以看出:强引用与软引用在内存不足时的回收情况。

2.3. 弱引用(Weak Reference)

只具有弱引用的对象拥有更短暂生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

创建弱引用,使用WeakReference

public static void main(String[] args) {String str = new String("abc");WeakReference<String> weakReference = new WeakReference<>(str);str = null;System.gc();// 一旦发生GC,弱引用一定会被回收System.out.println(weakReference.get());//结果为null}

2.4. 虚引用(Phantom Reference)

虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,完全不会对其生存时间构成影响,它就和没有任何引用一样,随时可能会被回收。

虚引用,主要用来跟踪对象被垃圾回收的活动,可以在垃圾收集时收到一个系统通知。

3.垃圾收集算法

2.1. 分代收集理论

目前主流JVM虚拟机中的垃圾收集器,都遵循分代收集理论:

  • 弱分代:绝大多数对象都是朝生夕灭
  • 强分代:经历越多次垃圾收集过程的对象,越难以回收,难以消亡

        按照分代收集理论设计的“分代垃圾收集器”,所采用的设计原则:收集器应该将Java堆划分成不同的区域,然后将回收对象依据其年龄(年龄即对象经历过垃圾收集过程的次数)分配到不同的区域存储。

2.2.分代存储

如果一个区域中大多数对象都是朝生夕灭(新生代),难以熬过垃圾收集过程的话,把它们集中存储在一起,每次回收时,只关注如何保留少量存活对象,而不是去标记大量将要回收的对象,就能以较低代价回收到大量的空间。

如果一个区域中大多数对象都是难以回收(老年代),那么把它们集中放在一起,JVM虚拟机就可以使用较低的频率,来对这个区域进行回收。

2.3.分代收集

垃圾收集类型划分:

  • 部分收集(Partial GC):没有完整收集整个Java堆的垃圾收集,其中又分为:
    • 新生代收集(Minor GC / Young GC
    • 老年代收集(Major GC / Old GC
    • 混合收集(Mixed GC):收集整个新生代和部分老年代的垃圾收集。
  • 整堆收集(Full GC):收集整个Java堆的垃圾收集。

2.4.具体垃圾收集算法

Java堆区划分成不同区域后,垃圾收集器才可以针对不同的区域,安排与该区域存储对象存亡特征相匹配的垃圾收集算法:标记-复制算法标记-清除算法标记-整理算法等。

2.4.1.标记-清除算法( Mark-Sweep )

实现思路:

        分为“标记”和“清除”阶段:首先标记出所有不需要回收的对象,在标记完成后统一回收掉所有没有被标记的对象。它是最基础的收集算法,后续的算法都是对其不足进行改进得到。

存在的问题:

  1. 执行效率不稳定问题:如果执行垃圾收集的区域,大部分对象是需要被回收的,则需要大量的标记和清除动作,导致效率变低。
  2. 内存空间碎片化问题:标记清除后会产生大量不连续的碎片,空间碎片太多,会导致分配较大对象时,无法找到足够的连续空间,从而会触发新的垃圾收集动作。

 黑色:可回收对象      蓝色:存活对象       白色:未使用空间

2.4.2.标记-复制算法 ( Copying )

        “标记-复制”收集算法简称“复制算法”,为了解决“标记-清除”面对大量可回收对象时执行效率低下的问题。

实现思路:
        该算法将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把已使用的空间一次清理掉。

存在的问题:

  1. 对象存活率较高,需要进行较多的内存间复制,效率降低
  2. 浪费过多的内存,使现有的可用空间变为原先的一半

2.4.3. 标记-整理算法 ( Mark-Compact )

实现思路:

        标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行回收,而是让所有存活的对象向内存空间一端移动, 然后直接清理边界以外的内存,这样清理的机制,不会像标记-清除那样留下大量的内存碎片。

综上所述:

        当前虚拟机的垃圾收集都基于分代收集思想,根据对象存活周期的不同,将内存分为几个不同的区域,在不同的区域选择使用合适的垃圾收集算法

例如:Heap 堆分为新生代老年代,这样我们就可以根据各个年代的特点,从存活几率和额外的空间中选择合适的垃圾收集算法,

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue基础知识八:为什么data属性是一个函数而不是一个对象?

一、实例和组件定义data的区别 vue实例的时候定义data属性既可以是一个对象&#xff0c;也可以是一个函数 const app new Vue({el:"#app",// 对象格式data:{foo:"foo"},// 函数格式data(){return {foo:"foo"}} })组件中定义data属性&#xff…

网站文章生成技术-网站文章生成工具免费

大家好&#xff0c;今天我想和大家分享一些关于网站文章生成的疑虑和期待。作为一个常常需要在网站上发布文章的人&#xff0c;我对这项技术的发展充满了好奇和担忧。在这篇文章中&#xff0c;我将坦率地表达我的想法&#xff0c;希望能引发一些思考。 让我谈一谈我的疑虑。网站…

基于SSM的农产品仓库管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

TypeScript命名空间和模块

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 命名空间&#xff08;Namespace&#xff09; 命名空间&#xff08;Namespace&#xff09;使用场景 第三方库 兼容…

【C语言】【strcpy的使用和模拟实现】

1.strcpy的使用&#xff1a; char* strcpy(char* destination,const char* source)返回类型是字符指针&#xff0c;参数是接受方字符串的首地址和要拷贝的字符串的首地址 从接受地的‘\0’开始拷贝&#xff0c;会将源字符串中的’\0’也拷贝过来目标空间必须足够大&#xff0…

【JavaEE】_CSS引入方式与选择器

目录 1. 基本语法格式 2. 引入方式 2.1 内部样式 2.2 内联样式 2.3 外部样式 3. 基础选择器 3.1 标签选择器 3.2 类选择器 3.3 ID选择器 4. 复合选择器 4.1 后代选择器 4.2 子选择器 4.3 并集选择器 4.4 伪类选择器 1. 基本语法格式 选择器若干属性声明 2. 引入…

terraform简单的开始-安装和一些配置

terraform的安装&#xff1a; 官方下载&#xff1a; 浏览器打开terraform官方主页https://www.terraform.io/ 点击Download Terraform 跳转到程序下载页面&#xff1a; 找到自己对应的操作系统&#xff0c;按照操作系统选择安装terraform的方式&#xff1a; linux为例&…

LabVIEW利用人工神经网络辅助进行结冰检测

LabVIEW利用人工神经网络辅助进行结冰检测 结冰对各个领域构成重大威胁&#xff0c;包括但不限于航空航天和风力涡轮机行业。在起飞过程中&#xff0c;飞机机翼上轻微积冰会导致升力降低25%。研究报告称&#xff0c;涡轮叶片上的冰堆积可在19个月的运行时间内造成29MWh的功率损…

《86盒应用于家居中控》——实现智能家居的灵动掌控

近年来&#xff0c;智能家居产品受到越来越多消费者的关注&#xff0c;其便捷、舒适的生活方式让人们对未来生活充满期待。作为智能家居方案领域的方案商&#xff0c;启明智显生产设计的86盒凭借出色的性能和良好的用户体验&#xff0c;成功应用于家居中控系统&#xff0c;让家…

数据在内存中的存储——练习3

题目&#xff1a; 3.1 #include <stdio.h> int main() {char a -128;printf("%u\n",a);return 0; }3.2 #include <stdio.h> int main() {char a 128;printf("%u\n",a);return 0; }思路分析&#xff1a; 首先二者极其相似%u是无符号格式进行…

基于SSM的旅游网站系统

基于SSM的旅游网站系统【附源码文档】、前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 【主要功能】 角色&#xff1a;管理员、用户 管理员&#xff1a;用户管理、景点…

【Linux】多线程互斥与同步

文章目录 一、线程互斥1. 线程互斥的引出2. 互斥量3. 互斥锁的实现原理 二、可重入和线程安全三、线程和互斥锁的封装1. 线程封装1. 互斥锁封装 四、死锁1. 死锁的概念2. 死锁的四个必要条件3. 避免死锁 五、线程同步1. 线程同步的理解2. 条件变量 一、线程互斥 1. 线程互斥的…

教你制作作业查询系统

嗨&#xff0c;各位老师们&#xff0c;今天我要给你们介绍一个超级方便的工具——易查分&#xff01;你知道吗&#xff0c;利用易查分&#xff0c;我们可以轻松制作一个便捷高效的作业查询系统哦&#xff01; 是不是想有个自己的分班or成绩查询页面&#xff1f;博主给老师们争取…

使用js搭建简易的WebRTC实现视频直播

首先需要一个信令服务器&#xff0c;我们使用nodejs来搭建。两个端&#xff1a;发送端和接收端。我的目录结构如下图&#xff1a;流程 创建一个文件夹 WebRTC-Test。进入文件夹中&#xff0c;新建一个node的文件夹。使用终端并进入node的目录下&#xff0c;使用 npm init 创建p…

01-从JDK源码级别剖析JVM类加载机制

上一篇&#xff1a;JVM虚拟机调优大全 1. 类加载运行全过程 当我们用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把主类加载到JVM。 public class Math {public static final int initData 666;public static User user new User();public i…

20230913java面经整理

1.hashmap为什么重写hashcode必须重写equals&#xff1f;不重写hashcode&#xff1f; hashcode判断对象存放的索引值&#xff0c;equals判断相同索引下对象是否相同&#xff0c;不同则存放&#xff08;链表&#xff09; hashcode提升查询效率&#xff0c;通过哈希计算&#xf…

性能测试 —— Jmeter定时器

固定定时器 如果你需要让每个线程在请求之前按相同的指定时间停顿&#xff0c;那么可以使用这个定时器&#xff1b;需要注意的是&#xff0c;固定定时器的延时不会计入单个sampler的响应时间&#xff0c;但会计入事务控制器的时间 1、使用固定定时器位置在http请求中&#xf…

idea中的debug界面上没有进入方法的红色按钮

问题描述&#xff1a; 这里缺少进入系统方法的红色按钮。 问题解决方法&#xff1a; 在上面图片红框范围内右键点击进入。 点击号 搜索 ‘force’ 添加即可完成 上下拖动即可调整界面按钮顺序

Azure + React + ASP.NET Core 项目笔记一:项目环境搭建(一)

不重要的目录标题 前提条件第一步&#xff1a;新建文件夹第二步&#xff1a;使用VS/ VS code/cmd 打开该文件夹第三步&#xff1a;安装依赖第四步&#xff1a;试运行react第五步&#xff1a;整理项目结构 前提条件 安装dotnet core sdk 安装Node.js npm 第一步&#xff1a;新…

Linux下的系统编程——进程间的通信(九)

前言&#xff1a; 前面我们已经对进程已经有了一个简单的了解与认识&#xff0c;那么进程间的通信是什么样的呢&#xff0c;什么是父子进程&#xff0c;什么是兄弟进程&#xff0c;没有血缘关系间的进程是如何实现进程通信的&#xff0c;下面让我们一起学习一下什么是进程间的…