当前位置: 首页 > news >正文

JVM垃圾回收

概述

  • Java是支持自动垃圾回收的,有些语言不支持自动垃圾回收(C++)
  • 自动垃圾回收不是Java的首创

垃圾是什么?

  • 在 JVM 中垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。

哪些区域需要回收垃圾?

  • 堆,方法区

为什么要GC

  • 如果不及时对内存进行垃圾清理,那么,这些垃圾所占的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用,甚至可能导致内存溢出,也就是常说的 OOM
  • 在回收时还可以将内存碎片进行整理(数组必须使用连续空间)

内存溢出和内存泄露

  • 内存溢出:经过垃圾回收后,内存中仍然无法储存创建的新对象,内存不够用溢出。
  • 内存泄露:IO流 close jdbc连接 close 没有关闭,一些对象已经不使用了,但是垃圾回收器不能将其判定为垃圾,这些对象就在后台默默占用内存,这种情况被称为内存泄露,大量的这种对象存在,一是导致内存溢出的原因。

自动垃圾回收

  • 好处: 解放程序员,对内存的管理更加合理,自动化
  • 坏处: 会影响程序员在内存管理方面的能力,如果出现异常无法精准定位问题所在
    在回收次数上频繁收集新生代Young区,较少收集Old区,基本不手机方法区(元空间)

垃圾回收相关算法

标记阶段算法

  • 判断你对象是否是垃圾对象,是否有引用指向对象

引用计数法(Reference Couting)(在现在的JVM中没有使用)

  • 有个计数器来计算对象的引用数量
	String s1 = new String("aaa");String s2 = s1; //有两个引用变量指向aaas2 = null; -1s1 = null; -1//最终指向aaa的引用变量为0

优点: 实现简单,垃圾对象容易辨识;判定效率高,回收没有延迟性
确定: 需要单独的字段存储计数器,这样的做法增加了存储空间的开销;每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了时间开销;最严重的问题是,无法处理循环引用的情况(多个对象之间互相引用,没有其他外部引用指向他们,计数器不为0不能回收,产生内存泄露),因此在Java中垃圾回收器中没有这类算法。

可达性分析算法(跟搜索算法)

  • 实现思路:从一些为跟对象(GCRoots)的对象出发去查找,与根据对象直接或间接连接的对象就是存活对象,不与跟对象引用连接的对象就是垃圾对象
    在这里插入图片描述

GC Roots 可以是哪些元素?

  • 在虚拟机栈中引用的对象
  • 方法区中存储的静态成员指向的独享
  • 作为同步锁使用的synchronized
  • 在虚拟机内部使用的对象

对象的finalization机制

  • 在对象销毁之前还会调用finalize()方法

  • 当一个对象被标记为垃圾后,在真正被回收之前会调用一次object类中的finalize()方法
    -ps:自己不要调用finalize,留给垃圾回收器去调用

  • 由于 finalize()方法的存在,虚拟机中的对象一般处于三种可能的状态:
    可触及的:从根节点开始,可以到达这个对象。这种对象不是垃圾,不用回收
    可复活的:对象的所有引用都被释放,但是对象有可能在 finalize()中复活。
    不可触及的:对象的 finalize()被调用,并且没有复活,那么就会进入不可触及状态。此时这种对象就是必须被回收的垃圾。
    以上 3 种状态中是由于 finalize()方法的存在,进行的区分。只有在对象不可触及时才可以被回收

具体流程:
判定一个对象obj是否被能被回收,需要进行两次标记过程:

  • 如果obj 到GCRoot没有引用链,进行第一次标记
  • 进行进一步筛选:
    • 如果obj没有重写finalize方法,或者已经被调用过一次,则obj被判定为不可触及的,进行回收
    • 如果obj重写了finalize方法,且没有被执行过,则obj会被插入到队列中,由一个由jvm自动创建的低优先级Finalizer线程,触发其finalize方法
    • 在该线程中,如果obj在finalize方法中与GCRoots上的任何一个对象创建了联系,那么在第二次标记的时候obj就会被移出“即将被回收”的集合里,完成复活。如果再次出现没有引用的情况,finalize方法就不会再次触发
public class CanReliveObj {public static CanReliveObj obj;//类变量,属于 GC Root//此方法只能被调用一次@Overrideprotected void finalize() throws Throwable {//super.finalize();System.out.println("调用当前类重写的finalize()方法");obj = this;//当前待回收的对象在finalize()方法中与引用链上的一个对象obj建立了联系}public static void main(String[] args) {try {obj = new CanReliveObj();// 对象第一次成功拯救自己obj = null;System.gc();//调用垃圾回收器,触发FULL GC  也不是调用后立刻就回收的,因为线程的执行权在操作系统System.out.println("第1次 gc");// 因为Finalizer线程优先级很低,暂停2秒,以等待它Thread.sleep(2000);if (obj == null) {System.out.println("obj is dead");} else {System.out.println("obj is still alive");}System.out.println("第2次 gc");// 下面这段代码与上面的完全相同,但是这次自救却失败了obj= null;System.gc();// 因为Finalizer线程优先级很低,暂停2秒,以等待它Thread.sleep(2000);if (obj == null) {System.out.println("obj is dead");} else {System.out.println("obj is still alive");}} catch (InterruptedException e) {e.printStackTrace();}}
}/**
控制台输出结果:第一次 gc调用当前重写的finalize()方法obj is still alive第二次 gcobj is dead
*/

垃圾回收阶段算法

标记-复制算法:

  • 将内存分为大小相等的两份,把当前使用的空间中存活的对象复制到另一个空间中,将正在使用的空间中垃圾对象清除。
    优点:可以减少内存碎片
    缺点:如果需要复制的对象数量多,效率就会低
    适用场景:存活对象少 新生代适合使用标记复制算法

标记-清除算法:

  • 清除不是真正的把对象垃圾清除掉
  • 将垃圾对象地址维护到一个空闲列表中,后面有新对象到来时,覆盖掉垃圾对象即可。
  • 特点:
    • 实现简单
    • 效率低,回收后有碎片产生

在这里插入图片描述

标记-压缩算法(标记-整理):

  • 先从根节点标记所有被应用对象,然后将所有存活对象压到内存的一端,按顺序排放。之后清除边界外的所有空间
  • 特点
    • 消除了标记-清除算法中的碎片空间,解决了标记-复制算法需要2倍空间的问题
    • 从效率上来说是三种算法中最慢的;移动对象的同时如果对象被其他对象引用,还需要引用对象的地址;在移动过程中会暂停用户应用程序,造成STW

在这里插入图片描述
标记-压缩算法与标记-清除算法的比较

  • 标记-压缩算法的最终效果等同于标记-清除算法执行完成后,再进行一次内存碎片整理,因此,也可以把它称为标记-清除-压缩(Mark-Sweep-Compact)算法
  • 二者的本质差异在于标记-清除算法是一种非移动式的回收算法(空闲列表记录位置),标记-压缩是移动式的。是否移动回收后的存活对象是一项优缺点并存的风险决策。
  • 可以看到,标记的存活对象将会被整理,按照内存地址依次排列,而未被标记的内存会被清理掉。如此一来,当我们需要给新对象分配内存时,JVM 只需要持有一个内存的起始地址即可,这比维护一个空闲列表显然少了许多开销。

垃圾回收算法小结

效率上来说,复制算法是当之无愧的老大,但是却浪费了太多内存。
而为了尽量兼顾上面提到的三个指标,标记-压缩算法相对来说更平滑一些,但是效率上不尽如人意,它比复制算法多了一个标记的阶段,比标记-清除多了一个整理内存的阶段。

在这里插入图片描述

垃圾回收相关概念

System.gc()

  • 默认情况下,通过System.gc()或者Runtime.getRuntime().gc()的调用会显示触发Full GC,同时对老年代新生代进行回收,尝试释放丢弃对象占用的内存
  • 一般情况下不手动进行System.gc(),在特殊情况下可以使用

STW(Stop The World)

  • 指的是在进行GC时,会产生应用程序的停顿,这种停顿会让整个应用程序线程都停掉无响应,有点像卡顿,这样的情况被称为STW

垃圾回收器

  • 垃圾回收器是垃圾回收的具体实现者,垃圾回收算法是垃圾回收器的方法论

垃圾回收器分类

  • 按照线程数量:
    单线程回收器(Serial,Serial old)
    多线程回收器(Parallel)
    单线程垃圾回收器
    只有一个线程进行垃圾回收,适用于简单小型的使用场景,垃圾回收时其他用户线程会暂停。
    在这里插入图片描述

多线程垃圾回收器
使用多个线程进行垃圾回收,在多CPU的情况下大大的提升了垃圾回收的效率 同样会停止用户线程
在这里插入图片描述

  • 按照工作模式:
    独占式:垃圾回收线程执行时,其他线程暂停
    并行式:垃圾回收线程可以和用户线程同时执行(只在一部分阶段并行)
    **独占式垃圾回收器**
**并行式垃圾回收器**

  • 按照工作内存区间:

  • 老年代垃圾回收器

  • 年轻代垃圾回收器
    *下图展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,则说明他们能搭配使用。虚拟机所处的区域则代表他们存在于新生代还是老年代收集器。
    在这里插入图片描述

垃圾回收指标

  • 吞吐量:运行用户代码占总运行代码的时间
  • 垃圾收集开销:垃圾收集占用的时间与总运行时间的比例
  • 暂停时间:执行垃圾收集时占用的时间
  • 回收的速度
  • 占用内存大小:Java堆区所占用内存的大小

CMS垃圾回收器

  • CMS(ConcurrentMarkSweep,并发标记清除)是以获取最短停顿时间为目标的垃圾回收器,它在垃圾回收时使得用户线程和回收线程并发执行,因此在垃圾收集过程中用户也不会感到明显的卡顿

垃圾回收的过程

  • 初始标记:先进行STW,使用一条初始线程对所有与GCRoots直接关联的对象进行标记;
  • 并发标记:垃圾回收线程与用户线程并行,在此过程中进行可达性分析,标记处所有需要回收的废弃对象
  • 重新标记:STW,使用多条标记线程并发执行,并将刚才过程中新出现的废弃对象标记出来
  • 并发清除:使用一条GC线程,与用户线程并发执行,清除刚才标记的对象,这个过程最耗时。

在这里插入图片描述

由于并发标记和并发清除耗时最长,且可以与用户线程同时工作,因此总体上来说CMS收集器的内存回收过程是与用户线程一起并发执行的。

CMS的优点
可以做到并发收集

CMS的弊端
1.CMS 是基于标记-清除算法来实现的,会产生内存碎片。
2.CMS 在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分
线程而导致应用程序变慢,总吞吐量会降低。
3.CMS 收集器无法处理浮动垃圾(floating garbage)。

三色标记算法(CMS)

  • 由于CMS有并发执行的过程,所以在标记垃圾对象时,有不确定性。
  • 所以在标记时将对象分为三种状态
  • 黑色:例如GCRoots 确定是存活的对象
  • 灰色:与黑色对象关联的对象,其中还有未扫描完的,之后还需要再次扫描
  • 白色:与黑色灰色都无关联的,垃圾收集算法不可达的对象

三色标记的过程:
1.先确立GCRoots,把GCRoots标记为黑色
2.与GCRoots相连接的标记为灰色
3.再次遍历灰色,灰色变为黑色,如果原来灰色下面有关联其他对象,则将其变为灰色。
4.重复步骤3,最终只保留黑色,灰色,回收白色对象
可能会出现漏标和错标的现象

  • 漏标:假设 GC 已经在遍历对象 B 了,而此时用户线程执行了 A.B=null 的操作,切断了 A 到 B 的引用,本来执行了 A.B=null 之后,B、D、E 都可以被回收了,但是由于 B 已经变为灰色,它仍会被当做存活对象,继续遍历下去。最终的结果就是本轮 GC 不会回收 B、D、E,留到下次 GC 时回收,也算是浮动垃圾的一部分。
    在这里插入图片描述
  • 错标:假设 GC 线程已经遍历到 B 了,此时用户线程执行了以下操作:B.D=null;//B 到 D 的引用被切断A.xx=D;//A 到 D 的引用被建立B 到 D 的引用被切断,且 A 到 D 的引用被建立。此时 GC 线程继续工作,由于 B 不再引用 D 了,尽管 A 又引用了 D,但是因为 A 已经标记为黑色,GC 不会再遍历 A 了,所以 D 会被标记为白色,最后被当做垃圾回收。可以看到错标的结果比漏表严重的多,浮动垃圾可以下次 GC 清理,而把不该回收的对象回收掉,将会造成程序运行错误。
  • 在这里插入图片描述

解决错标的问题
错标只有满足:灰色指向白色的引用全部断开;黑色建立了指向白色的引用;这两种情况才会发生,只需要解决这两种的其中一种原因就能避免错标的问题
解决办法:原始快照和增量更新。
原始快照打破的是第一个条件:当灰色对象指向白色对象的引用被断开时,就将这条引用关系记录下来。当扫描结束后,再以这些灰色对象为根,重新扫描一次。增量更新打破的是第二个条件:当黑色指向白色的引用被建立时,就将这个新的引用关系记录下来,等扫描结束后,再以这些记录中的黑色对象为根,重新扫描一次。相当于黑色对象一旦建立了指向白色对象的引用,就会变为灰色对象。
G1回收器(Garbage-First)

  • 将堆内存的各个区域又分为较小的多个区,对这些个区域进行监测,对某一个区域中垃圾数量大的区域优先回收,也是并发收集的。
  • G1主要针对配备多核 CPU 及大容量内存的机器,以极高概率满足 GC 停顿时间的同时,还兼具高吞吐量的性能特征
    适用场景:要求尽可能可控 GC 停顿时间;内存占用较大的应用

查看 JVM 垃圾回收器设置垃圾回收

//打印默认垃圾回收器
-XX:+PrintCommandLineFlags -version
JDK 8 默认的垃圾回收器
//年轻代使用 Parallel Scavenge GC
//老年代使用 Parallel Old GC
//打印垃圾回收详细信息
-XX:+PrintGCDetails -version
//设置默认垃圾回收器
//Serial 回收器
-XX:+UseSerialGC 年轻代使用 Serial GC, 老年代使用 Serial Old GC
//ParNew 回收器
-XX:+UseParNewGC 年轻代使用 ParNew GC,不影响老年代。CMS 回收器
-XX:+UseConcMarkSweepGC 老年代使用 CMS GCG1 回收器
-XX:+UseG1GC 手动指定使用 G1 收集器执行内存回收任务。
-XX:G1HeapRegionSize 设置每个 Region 的大小

相关文章:

JVM垃圾回收

概述 Java是支持自动垃圾回收的,有些语言不支持自动垃圾回收(C)自动垃圾回收不是Java的首创 垃圾是什么? 在 JVM 中垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。 哪些区域需要回收…...

clickhouse集群安装

单机安装 yum install yum-utilsrpm --import https://repo.clickhouse.com/CLICKHOUSE-KEY.GPGyum-config-manager --add-repo https://repo.clickhouse.com/rpm/clickhouse.reposudo yum install clickhouse-server clickhouse-client 配置文件 vim /etc/clickhouse-serve…...

Zookeeper入门

Zookeeper入门概述特点结构应用场景选举机制节点信息监听原理写数据原理分布式锁概述 Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。 Zookeeper 从设计模式的角度来开:是一个基于观察者模式设计的分布式服务管理框架&#xf…...

JavaScript

BOM核心对象docunmentBOM核心对象windowBOM包含着DOMF12即可打开浏览器控制台navigator(浏览器版本)、history(浏览器历史记录),location(地址信息)、screen(屏幕相关)JS输出形式:浏览器输出:wi…...

.gitignore 常用忽略规则

.gitignore常用忽略语法 1、空格不匹配任意文件,可作为分隔符,可用反斜杠转义 2、以井号#开头的文件标识注释,可以使用反斜杠进行转义 3、以斜杠/开头表示目录 4、以星号*通配多个字符 5、以问号?通配单个字符 6、以方括号[]包含单个字符的…...

Vue路由 —— vue-router

在上一篇内容讲到关于单页面组件的内容,同时也附上补充讲了关于单页面(SPA)和多页面(MPA)之间的优缺点,在本篇目当中就要来讲这个路由(vue-router),通过路由来实现页面的…...

Java Jackson TypeReference获取泛型类型信息【泛型】

Jackson是一个比较流行的Json序列化和反序列化框架。本文以Jackson为例介绍TypeReference实现涉及泛型的反序列化,及TyperReference的实现原理。对于获取泛型类型信息的场景,TypeReference是一个可以参考的通用解决方案。 Jackson ObjectMapper的readVa…...

Python 核心笔记(二)

特殊规则及特殊字符:#号(#) : 注释换行(\n) : 换行反斜线(\) : 继续上一行分号(;) : 两个语句连在一行冒号(:) : 将代码块的头和体分开不同的缩进…...

Hadoop集群搭建

文章目录一、运行环境配置(所有节点)1、基础配置2、配置Host二、依赖软件安装(101节点)1、安装JDK2、安装Hadoop(root)3、Hadoop目录结构三、本地运行模式(官方WordCount)1、简介2、本地运行模式(官方WordCount)四、完全分布式运行…...

每个前端都应该掌握的7个代码优化的小技巧

本文将介绍7种JavaScript的优化技巧,这些技巧可以帮助你更好的写出简洁优雅的代码。 1. 字符串的自动匹配(Array.includes) 在写代码时我们经常会遇到这样的需求,我们需要检查某个字符串是否是符合我们的规定的字符串之一。最常…...

金三银四丨黑蛋老师带你剖析-二进制漏洞

作者:黑蛋二进制漏洞岗上篇文章我们初步了解了一下简历投递方式以及二进制方向相关逆向岗位的要求,今天我们就来看看二进制漏洞相关的岗位,当然,漏洞岗位除了分不同平台,也有漏洞挖掘岗和漏洞分析利用岗。同样&#xf…...

pgsql-用户角色组角色创建和维护

pgsql-用户&角色&组角色创建和维护 环境 win10pgsql 14.2 相关文档 PostgreSQL 14.1 手册 create 语法 grant 授权语法 revoke 撤回语法 alter 更新语法 用户、角色、组角色概念和区别 早期版本(8.1之前)中用户、组、角色是不同的概念&#…...

算法与数据结构理解

目录1、数据结构与算法1.1 定义1.2 常见数据结构1.3 常用算法2、插入排序3、希尔排序4、归并排序1、数据结构与算法 1.1 定义 数据结构:是计算机中存储、组织数据的方式。具有一定逻辑关系,应用某种存储结构,并且封装了相应操作的数据元素集…...

常见的C++软件异常场景分析与总结

根据排查软件异常问题的经历和经验,简单的总结一下软件异常的场景和原因,以供参考。 1、野指针问题 可能是指针没初始化就使用。也有可能是指针指向的内存已经被释放,但是指针没置为NULL,一旦访问这样的指针就会出问题。在很多情…...

【虹科公告】好消息!云展厅开放时间长达1年,2023年不限次云观展

云展厅开放通知 2023年,【虹科赋能汽车智能化云展厅】将持续开放,开放时间长达一年,开放期内,均可进入观展,没有次数及观看时长限制,欢迎大家随时进入云展厅观展。 虹科赋能汽车智能化云展厅 聚焦前沿技…...

Linux破解root密码

✅作者简介:热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏:Linux操作…...

2023年信息与通信工程国际会议(JCICE 2023)

2023年信息与通信工程国际会议(JCICE 2023) 重要信息 会议网址:www.jcice.org 会议时间:2023年3月17-19日 召开地点:成都 截稿时间:2023年2月10日 录用通知:投稿后2周内 收录检索:EI,Scopus 会议简介…...

ASP.NET Core+Element+SQL Server开发校园图书管理系统(完)

随着技术的进步,跨平台开发已经成为了标配,在此大背景下,ASP.NET Core也应运而生。本文主要基于ASP.NET CoreElementSql Server开发一个校园图书管理系统为例,简述基于MVC三层架构开发的常见知识点,本系列共五篇文章&a…...

elasticsearch 批量写入(Python版).md

1. 插入数据 现在我们如果有大量的文档(例如10000000万条文档)需要写入es 的某条索引中,该怎么办呢? 1.1 顺序插入 import time from elasticsearch import Elasticsearches Elasticsearch()def timer(func):def wrapper(*arg…...

【排序算法】快速排序(Quick Sort)

快速排序(Quick Sort)使用分治法算法思想。快速排序介绍它的基本思想是: 选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小。然后,再按此方法对这两部分数据分别进行快速排…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…...

消息队列系统设计与实践全解析

文章目录 &#x1f680; 消息队列系统设计与实践全解析&#x1f50d; 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡&#x1f4a1; 权衡决策框架 1.3 运维复杂度评估&#x1f527; 运维成本降低策略 &#x1f3d7;️ 二、典型架构设计2.1 分布式事务最终一致…...

Modbus RTU与Modbus TCP详解指南

目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...