Java虚拟机(JVM):引用计数算法

一、引言

我们学习了Java内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭。栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来就已知的,因此这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需要过多考虑如何回收的问题,当方法结束或者线程结束时,内存自然就跟随着回收了。

而Java堆和方法区这两个区域则有着很显著的不确定性:一个接口的多个实现类需要的内存可能会不一样,一个方法所执行的不同条件分支所需要的内存也可能不一样,只有处于运行期间,我们才能知道程序究竟会创建哪些对象,创建多少个对象,这部分内存的分配和回收是动态的。垃圾收集器所关注的正是这部分内存该如何管理,一般讨论“内存”分配与回收也仅仅特指这一部分。

二、引用计数算法

引用计数算法是一种内存管理算法,用于追踪对象的引用数量。它的基本原理是为每个对象维护一个计数器,记录当前有多少个指针指向该对象。当计数器的值变为0时,表示该对象不再被引用,可以被回收。

引用计数算法的实现思路如下:

  1. 在对象中添加一个引用计数器,初始值为0。
  2. 当有一个指针指向该对象时,引用计数器加1。
  3. 当一个指针不再指向该对象时,引用计数器减1。
  4. 当引用计数器的值为0时,表示没有指针指向该对象,可以将该对象回收。

引用计数算法的优点:

  1. 实时性:引用计数算法可以实时地进行内存回收,不需要等待垃圾回收器的运行。
  2. 简单高效:引用计数算法的实现相对简单,不需要遍历整个对象图,只需要维护计数器即可。

引用计数算法的缺点:

  1. 循环引用问题:当存在循环引用时,引用计数算法无法正确地回收内存。例如,对象A和对象B相互引用,它们的引用计数器都不会变为0,导致内存泄漏。
  2. 计数器更新开销:每次引用发生变化时,都需要更新计数器,导致额外的开销。

因为引用计数算法存在循环引用问题,所以现代的垃圾回收器往往不使用纯粹的引用计数算法,而是采用其他算法(如标记-清除算法、复制算法、标记-整理算法等)与引用计数算法结合,来解决循环引用的回收问题。

三、代码分析

以下是一个简单的引用计数算法的代码案例:

class ReferenceCounting {private int count; // 引用计数器public ReferenceCounting() {count = 0;}public void addReference() {count++;}public void removeReference() {count--;}public int getCount() {return count;}
}
class Object {private ReferenceCounting refCount; // 引用计数对象public Object() {refCount = new ReferenceCounting();refCount.addReference(); // 对象创建时增加引用计数}public void addReference() {refCount.addReference();}public void removeReference() {refCount.removeReference();if (refCount.getCount() == 0) {// 引用计数为0时执行回收操作System.out.println("Object is reclaimed.");// 执行回收操作}}
}
public class ReferenceCountingDemo {public static void main(String[] args) {Object obj1 = new Object(); // 创建对象1Object obj2 = new Object(); // 创建对象2obj1.addReference(); // obj1引用计数加1obj1.addReference(); // obj1引用计数加1obj2.addReference(); // obj2引用计数加1obj1.removeReference(); // obj1引用计数减1obj1.removeReference(); // obj1引用计数减1,计数为0,执行回收操作obj2.removeReference(); // obj2引用计数减1,计数不为0,不执行回收操作}
}

在上述代码中,ReferenceCounting类是引用计数器类,用于记录对象被引用的次数。Object类是被引用的对象类,其中包含了一个ReferenceCounting对象。当创建对象时,引用计数加1,当移除对象引用时,引用计数减1。当引用计数为0时,表示对象不再被引用,可以执行回收操作。 在ReferenceCountingDemo类的main方法中,我们创建了两个对象obj1obj2,分别增加和减少引用计数,演示了引用计数算法的基本原理。

在下一个案例前,我们首先要学会在IDEA中输出gc日志信息:

循环引用代码分析:

class A {private B b;public void setB(B b) {this.b = b;}
}
class B {private A a;public void setA(A a) {this.a = a;}
}
public class ReferenceCountingDemo {public static void main(String[] args) {A a = new A();B b = new B();a.setB(b);b.setA(a);// 解除对A和B对象的引用a = null;b = null;// 这里无法回收A和B对象,因为它们之间存在循环引用System.gc();}
}

在上述案例中,我们创建了两个类A和B,它们分别有一个成员变量用于相互引用。在main方法中,我们创建了一个A对象和一个B对象,并通过setBsetA方法将它们相互引用起来。但是,由于它们之间存在循环引用,即A对象引用B对象,B对象引用A对象,导致它们的引用计数器都不会变为0,无法被回收。

尽管在最后我们将ab设置为null解除了对它们的引用,但由于循环引用的存在,它们的引用计数仍然不为0,无法执行回收操作。

 控制台输出:

从运行结果可以看到内存回收日志包含“Pause Full (System.gc()) 2M->0M(14M) 3.909ms”,意味着虚拟机并没有因为这两个对象互相引用就放弃回收它们,这也从侧面说明了Java虚拟机并不是通过引用计数算法来判断对象是否存活的。

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

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

相关文章

模板方法模式(十六)

相信自己,请一定要相信自己 上一章简单介绍了代理模式(十五), 如果没有看过, 请观看上一章 一. 模板模式 引用 菜鸟教程里面的 模板模式介绍: https://www.runoob.com/design-pattern/template-pattern.html 在模板模式(Template Pattern)…

VSCode好用的插件

文章目录 前言1.Snippet Creator & easy snippet(自定义代码)2.Indent Rainbow(代码缩进)3.Chinese (Simplified) Language Pack(中文包)4.Path Intellisense(路径提示)5.Beauti…

SpringBoo t+ Vue 微人事 (十一)

职位修改操作 在对话框里面做编辑的操作 添加对话框 <el-dialogtitle"修改职位":visible.sync"dialogVisible"width"30%"><div><el-tag>职位名称</el-tag><el-input size"small" class"updatePosIn…

在IDEA中创建properties配置文件

第一步&#xff1a;在 src路径下找到resources文件 第二步&#xff1a;右击选择新建Resource Bundle配置文件 第三步&#xff1a;为Resource Bundle配置文件命名 完成创建

Swift 周报 第三十五期

文章目录 前言新闻和社区五天市值蒸发 2000 亿美元&#xff0c;苹果公司怎么了&#xff1f;在你的 App 中帮助顾客解决账单问题需要声明原因的 API 列表现已推出 提案通过的提案正在审查的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组整理周报的第三十五…

【仿写tomcat】三、通过socket读取http请求信息

仿写tomcat 建立Socket连接获取连接信息查看HTTP信息 建立Socket连接 这里我们也是创建一个专门管理socket的类 package com.tomcatServer.socket;import java.io.*; import java.net.ServerSocket;/*** 套接字存储** author ez4sterben* date 2023/08/15*/ public class Soc…

使用 AI 将绘画和照片转换为动画

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可二次编辑器的3D应用场景 华盛顿大学和Facebook的研究人员最近发表了一篇论文&#xff0c;展示了一种基于深度学习的系统&#xff0c;可以将静止图像和绘画转换为动画。称为照片唤醒的算法使用卷积神经网络从单个静止图像以 …

滑块验证3-接第1篇

driver拖动滑块 滑块验证的过程比较常使用driver模拟滑动&#xff0c;这样能够省去很多验证操作。 如果设置适合的滑动轨迹&#xff0c;成功率是非常高的。 当然&#xff0c;麻烦的是现在很多站点都做了识别driver的反爬&#xff0c;而且比较受网络的影响。 所需包 seleniu…

C语言和JavaScript中的默认排序行为对比

前言 今天在js里使用sort时遇见了一个不理解的现象 即使用sort默认排序后 9 从排序前的第一位被排到了最后一位.一开始我对js sort的理解和c一样&#xff0c;然后通过查阅后发现并不是这样. 正文 排序是一项常见而重要的操作。不同的编程语言提供了不同的排序函数&#xf…

800V高压电驱动系统架构分析

需要电驱竞品样件请联&#xff1a;shbinzer &#xff08;拆车邦&#xff09; 过去一年是新能源汽车市场爆发的一年&#xff0c;据中汽协数据&#xff0c;2021年新能源汽车销售352万辆&#xff0c;同比大幅增长157.5%。新能源汽车技术发展迅速&#xff0c;畅销车辆在动力性能…

html | 基于iframe的简易富文本编辑器

效果图 支持: 选中后 ctrlI 斜体 代码 思路就是在iframe种嵌套html和css。 <pre> - 支持: 选中后 ctrlI 斜体 - todo: 鼠标实现单击斜体 </pre> <iframe name"richedit" style"height:30%; width:100%;"></iframe><script…

android framework-Pixel3真机系统内置第三方apk实战

一、在/packages/apps创建独一无二的文件夹TestCamera 二、拷贝第三方应用到TestCamera文件夹下 三、创建Android.mk LOCAL_PATH: $(call my-dir)include $(CLEAR_VARS) # Module name should match apk name to be installed LOCAL_MODULE : TestCamera LOCAL_MODULE_TAGS : o…

Android开发基础知识总结(一)初识安卓Android Studio

一.基础理论知识 1.Linux相当于是地基。 MIUI&#xff0c;EMUI等操作系统&#xff0c;是基于安卓的改版——且裁掉了一部分Google的服务。 &#xff08;鸿蒙虽然是改版&#xff0c;但和安卓的架构基本上一致&#xff09; 2.Kotlin和Java都是JVM语言&#xff0c;必须先复习好…

C#学习....

1.基础 //引用命名空间using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;//项目名或者命名空间 namespace _01_MY_First_Demo {//Program类class Program{//程序的主入口或者Main函数static void Main(S…

基于原生Servlet使用模板引擎Thymeleaf访问界面

我们常在Spring Boot项目中使用Thymeleaf模板引擎,今天突发奇想&#xff0c;尝试原生Servlet访问&#xff01; 说做就做 搭建完整的WEB项目 其中的大部分依赖都是后续报错 追加进来的 导入依赖 thymeleaf-3.0.11.RELEASE.jar 第一次访问 访问地址: http://localhost:8080…

BLFS学习系列 第25章. 图形环境库 —— libdrm

一、简介 libdrm提供了一个用户空间库&#xff0c;用于在支持ioctl接口的操作系统上访问直接渲染管理器&#xff08;DRM&#xff09;。libdrm是一个低级别库&#xff0c;通常由图形驱动&#xff08;程序&#xff09;使用&#xff0c;如Mesa DRI驱动&#xff08;程序&#xff0…

【记录】Python3|Selenium4 极速上手入门(Windows)

环境&#xff1a;Windows 版本&#xff1a;python3&#xff0c;selenium 4.11.2 写这个是方便自己重装电脑时重新装 Selenium&#xff0c;懒得每次都重新找链接。 文章目录 1 装ChromeEdge其他浏览器 2 运行报错RequestsDependencyWarning: urllib3 (1.26.9) or chardet (3.0.4…

几种常见的递归算法

阶乘 这个比较简单就不说了。 int factorial(int n) {if (n < 0){return 0;}else if (n 1){return 1;}else {return n * factorial(n - 1);} }fibonacci 如此简单的算法&#xff0c;复试的时候竟然写错了&#xff01;&#x1f633;囧&#xff01; int fibonacci(unsigne…

搭建开发环境-操作系统篇(一键搭建开发环境)

概述 所谓工欲善其事必先利其器&#xff0c;搭环境往往是开发过程中卡出很多初学者的拦路虎。 对于很多老鸟来说&#xff0c;很多东西都已经习惯成自然&#xff0c;也就没有刻意和初学者说。但对于很多初学者&#xff0c;却是受益良多。 这个系列&#xff0c;先从操作系统开始…

Docker容器与虚拟化技术:容器运行时说明与比较

目录 一、理论 1.容器运行时 2.容器运行时接口 3.容器运行时层级 4.容器运行时比较 5.强隔离容器 二、问题 1.K8S为何难以实现真正的多租户 三、总结 一、理论 1.容器运行时 &#xff08;1&#xff09;概念 Container Runtime 是运行于 k8s 集群每个节点中&#xff…