深入理解Java性能调优与JVM底层机制

Java作为一种广泛应用的编程语言,在企业级应用中占据着举足轻重的地位。随着系统规模的扩大和业务需求的复杂化,性能调优成为了开发过程中不可忽视的一环。Java的性能瓶颈往往并不直接来自代码本身,而是与JVM(Java虚拟机)底层机制、内存管理、垃圾回收等相关。

本文将深入探讨Java性能调优的基本策略,并解析JVM的底层机制,帮助开发者更好地理解和应对性能瓶颈。

一、性能调优的必要性

随着技术的进步,硬件性能的提升,越来越多的开发者开始关注系统软件层面的性能优化。Java程序在长时间运行后可能会遭遇性能下降的情况,这往往是由以下原因引起的:

  • 内存泄漏:内存管理不当会导致对象未被回收,逐渐占用过多内存。
  • GC性能瓶颈:垃圾回收机制可能会导致频繁的全GC,进而影响应用程序的响应速度。
  • 线程问题:线程池管理不当,或者多线程间的竞争可能引发死锁、线程阻塞等问题。
  • IO性能问题:过多的同步IO操作可能会成为性能瓶颈。

通过理解JVM底层机制及性能调优策略,可以更好地避免这些问题,提升Java应用程序的性能。

二、JVM的底层机制

要深入理解Java性能调优,首先必须了解JVM的底层机制,因为性能问题往往源自JVM的内存管理、垃圾回收和代码执行等核心部分。JVM(Java Virtual Machine)作为Java程序的执行环境,负责加载字节码、管理内存、执行代码和与底层操作系统交互。因此,掌握JVM的底层工作原理是优化Java应用程序性能的关键。

1. JVM架构概述

JVM作为Java程序的运行时环境,其主要目标是执行字节码,并将其转化为机器代码,使得Java程序可以在不同的硬件和操作系统平台上跨平台运行。JVM的主要组件包括:

  • 类加载器子系统:负责加载、链接和初始化Java类。类加载器子系统确保类在需要时才被加载,同时避免类的重复加载。
  • 运行时数据区:JVM使用运行时数据区来存储Java应用程序运行时的数据,包括堆内存、方法区、虚拟机栈、程序计数器等。
  • 执行引擎:负责执行字节码指令。它将字节码转化为机器指令并执行。JVM使用解释器和JIT编译器来提高程序的执行效率。
  • 垃圾回收器(GC) :负责回收不再使用的对象,清理内存,以便于新的对象分配。垃圾回收机制是JVM的重要特性之一,能够自动管理内存。
2. JVM内存模型

JVM的内存模型定义了程序运行时数据的存储方式和生命周期。内存模型中的每个区域都有特定的用途,理解这些内存区域的工作原理是进行性能优化的关键。

2.1 堆内存(Heap Memory)

堆是JVM内存区域中最大的部分,所有通过new关键字创建的对象都会存放在堆内存中。堆内存的大小可以通过JVM启动参数进行配置,例如-Xms设置堆的初始大小,-Xmx设置堆的最大大小。堆内存分为以下几个部分:

  • 年轻代(Young Generation) :用于存储新创建的对象。大多数对象在年轻代中存活时间较短,因此它们经常被垃圾回收。年轻代又分为三个区域:Eden区两个Survivor区(S0和S1)。
  • 老年代(Old Generation) :用于存储生命周期较长的对象。当一个对象经过多次GC(垃圾回收)仍然存活时,它会被晋升到老年代。
  • 持久代(Permanent Generation) :持久代用于存放JVM的类信息、常量池、静态变量等。在JDK 8之后,持久代被元空间(Metaspace) 替代,元空间存储了类的元数据。
2.2 方法区(Method Area)

方法区是JVM内存的一部分,用于存储被加载的类信息、常量、静态变量和JVM运行时常量池。方法区的内存设置通常依赖于操作系统的虚拟内存管理。JVM对方法区的内存管理不如堆内存灵活,因此在某些场景下可能会遇到OutOfMemoryError错误,特别是在类加载过多的情况下。

2.3 虚拟机栈(JVM Stack)

每个Java线程都会分配一个虚拟机栈,栈用于存储局部变量、方法调用和返回地址等数据。栈的生命周期与线程相同。当一个方法被调用时,会为该方法创建一个栈帧,栈帧用于存储方法的局部变量、操作数栈和方法返回的地址等信息。当方法执行完毕时,栈帧会被销毁。

虚拟机栈的大小可以通过-Xss参数进行设置,合理的栈大小可以避免栈溢出(StackOverflowError)。

2.4 程序计数器(Program Counter Register)

程序计数器是JVM的一种指令寄存器,它用于跟踪当前线程所执行的字节码指令的地址。每个线程都有一个独立的程序计数器,因为JVM是通过多线程并发执行的,线程间的程序计数器彼此独立。程序计数器在多线程的环境下,保证每个线程执行的指令顺序不会相互干扰。

2.5 本地方法栈(Native Method Stack)

本地方法栈主要用于支持JVM与本地方法的交互(通过JNI调用)。它为每个线程分配空间,存放调用本地方法时所需的局部变量和操作数。与虚拟机栈类似,本地方法栈也会在方法调用结束后释放相应的栈帧。

3. 垃圾回收机制(GC)

垃圾回收(GC)是JVM的核心功能之一,负责自动管理堆内存,回收那些不再被引用的对象,防止内存泄漏。垃圾回收的主要目标是优化内存使用,提高程序的响应能力。

JVM使用多种算法和垃圾回收器来实现内存回收,常见的垃圾回收算法包括:

  • 标记-清除算法:首先标记出所有需要回收的对象,然后清除这些对象。标记-清除算法的缺点是会产生内存碎片。
  • 复制算法:将内存分为两块,一块用于存活对象,另一块为空闲区域。每次垃圾回收时,将存活的对象从当前区域复制到空闲区域,清除当前区域。复制算法的优点是没有内存碎片,但它要求堆内存必须足够大。
  • 标记-整理算法:结合了标记-清除和复制算法的优点,标记出需要回收的对象,然后将存活对象移到堆的一端,最后清除剩余的内存区域。
  • 分代收集算法:将堆分为年轻代、老年代和永久代(JDK 8后为元空间)等不同的区域,针对不同的对象采用不同的回收策略。年轻代的垃圾回收频繁且代价较低,而老年代的垃圾回收则相对较少,且代价较大。

JVM中常见的垃圾回收器包括:

  • Serial GC:单线程回收器,适用于内存较小或单核系统。
  • Parallel GC:多线程回收器,适用于高吞吐量场景。
  • CMS GC(Concurrent Mark-Sweep GC) :低延迟回收器,适用于对响应时间要求较高的应用。
  • G1 GC:现代高效的垃圾回收器,能够提供可预测的GC停顿时间,适用于大规模应用。

JVM通过垃圾回收器的选择与配置来平衡性能与内存回收效率,减少GC对应用程序的影响。

4. JIT编译与热点代码优化

JVM的即时编译(JIT,Just-In-Time Compilation)技术是提升Java应用性能的关键。JIT编译器将字节码动态地编译成机器代码,以减少解释执行的性能开销。JVM通过监控运行时的代码执行情况,识别出热点代码(即执行频率较高的代码路径),并对其进行优化。

JIT编译器会根据代码的执行频率,采用不同的优化策略。例如,对于频繁执行的方法,JIT编译器会对其进行内联优化、循环展开、死代码消除等,极大提高代码的执行效率。

5. HotSpot虚拟机与性能优化

Oracle的HotSpot虚拟机是当前最常用的JVM实现之一。HotSpot虚拟机采用了动态编译、垃圾回收等多种优化技术,使得Java程序的运行效率大大提高。通过合理配置HotSpot虚拟机的参数,开发者可以根据不同的需求优化Java应用的性能。

JVM的底层机制涵盖了内存管理、垃圾回收、代码执行等多个方面。理解JVM的内存模型、垃圾回收算法、JIT编译优化和HotSpot虚拟机的工作原理,对于性能调优至关重要。通过合理配置JVM的内存、垃圾回收策略和优化代码执行路径,开发者可以有效提高Java应用程序的性能,确保其在高并发和大规模环境下的稳定运行。

三、Java性能调优策略

Java应用的性能调优是一个多方面的过程,涉及内存管理、垃圾回收、线程管理、IO优化以及代码执行的各个层面。在复杂的Java应用中,性能瓶颈可能源自多个方面,因此需要全面分析、定位并采取相应的调优策略。以下是一些常见的Java性能调优策略,帮助开发者提高应用程序的效率和响应能力。

1. 优化JVM内存管理

内存管理是Java性能调优的关键方面之一。合理配置JVM的内存参数、优化垃圾回收策略、避免内存泄漏等,都能有效提高应用程序的性能。

1.1 调整堆内存大小

JVM的堆内存是Java应用程序中用于存储对象实例的主要区域。合理的堆内存配置可以减少GC的频率和耗时,提高程序的响应速度。

  • -Xms:指定初始堆大小。默认情况下,JVM会根据系统内存自动设置堆的初始大小。为了避免频繁调整堆大小,可以通过设置-Xms为适当的初始值来减少堆扩展的次数。
  • -Xmx:指定最大堆大小。设置最大堆大小时,应该根据系统的可用内存和应用的内存需求进行调整。过小的堆大小会导致频繁的GC,而过大的堆则可能浪费内存资源。

通过合理调整-Xms-Xmx,可以避免堆的过度扩展和频繁的垃圾回收,确保应用在内存使用上更加高效。

1.2 选择合适的垃圾回收器

JVM提供了多种垃圾回收器,每个垃圾回收器的特性适用于不同的应用场景。根据应用的内存使用特点和性能需求选择合适的垃圾回收器,可以大大提高性能。

  • Serial GC:适用于内存较小或单核系统,使用单线程进行垃圾回收,性能较低。
  • Parallel GC:通过多线程垃圾回收来提高吞吐量,适用于大多数应用场景。
  • CMS GC(Concurrent Mark-Sweep GC) :适用于低延迟应用,可以减少应用停顿时间。
  • G1 GC:一种高效的低延迟垃圾回收器,适用于大规模应用。G1 GC可以提供更短的停顿时间,并能灵活控制停顿时间的最大值。

可以通过以下JVM参数来选择垃圾回收器:

bash

-XX:+UseParallelGC       # 使用Parallel GC
-XX:+UseG1GC             # 使用G1 GC
-XX:+UseConcMarkSweepGC  # 使用CMS GC
1.3 避免内存泄漏

内存泄漏会导致JVM堆内存不断被占用,最终引发OutOfMemoryError。常见的内存泄漏原因包括:

  • 长生命周期对象引用短生命周期对象:如集合类(List、Map)中保存了不再使用的对象,导致这些对象无法被GC回收。
  • 静态变量引用对象:静态变量的生命周期与应用程序相同,如果静态变量持有对对象的引用,该对象将无法被回收。

为了避免内存泄漏,应当确保及时释放不再使用的对象,尤其是在处理大量数据或使用第三方库时,注意其资源的释放。

2. 优化多线程和并发

多线程和并发是Java应用性能的一个重要方面。合理的线程管理和优化并发性能,可以显著提升系统的吞吐量和响应速度。

2.1 线程池优化

线程池是Java应用中管理线程的常用方式。通过合理配置线程池的大小和参数,可以提高线程的利用率,避免频繁创建和销毁线程带来的性能开销。

  • 线程池大小:线程池的大小应根据应用的并发量来调整。过小的线程池会导致任务队列积压,过大的线程池则可能导致上下文切换频繁,降低性能。一般来说,线程池大小可以通过CPU核心数 * 2 + 1来计算。
  • 合理设置队列长度:任务队列的长度应与系统的负载能力匹配。过长的队列会导致任务堆积,而过短的队列会导致频繁的线程切换。

可以通过以下方式配置线程池:

java

ExecutorService executorService = new ThreadPoolExecutor(corePoolSize,       // 核心池大小maximumPoolSize,    // 最大池大小keepAliveTime,      // 线程空闲时间TimeUnit.SECONDS,   // 时间单位new LinkedBlockingQueue<>(queueSize) // 队列大小
);
2.2 避免死锁和线程阻塞

死锁和线程阻塞是多线程应用中常见的性能瓶颈。死锁发生时,两个或多个线程相互等待对方释放资源,导致系统陷入永久等待状态。线程阻塞则是由于资源竞争、等待锁等原因,导致线程无法继续执行。

要避免死锁和线程阻塞,可以采取以下措施:

  • 使用锁的顺序来避免死锁,确保多个线程请求资源时按照相同的顺序进行。
  • 使用**tryLock()** 方法避免线程长时间等待锁。
  • 确保每个线程的锁粒度最小,避免锁的竞争过于激烈。
3. 优化I/O性能

I/O操作通常是Java应用中的性能瓶颈,尤其是在高并发或大量数据读写的场景中。优化I/O性能可以显著提高系统的响应速度和吞吐量。

3.1 使用NIO(New I/O)

Java的传统IO(java.io)是阻塞式的,效率较低。在需要高并发I/O操作时,可以使用NIO(Non-blocking I/O)来优化性能。NIO通过使用缓冲区(Buffer) 和通道(Channel) ,使得I/O操作变得更加高效。特别是在文件传输、网络通信等场景中,NIO能够显著减少阻塞等待时间,提升I/O性能。

NIO的核心特性:

  • 通道(Channel) :提供了一个连接数据源的通道,可以用来读取、写入数据。
  • 选择器(Selector) :用于处理多路复用I/O操作,允许一个线程处理多个I/O操作,从而减少线程的创建和切换开销。
3.2 异步I/O

对于长时间阻塞的I/O操作,可以使用异步I/O来优化性能。异步I/O使得线程在等待I/O操作时不会被阻塞,从而可以处理其他任务。在Java中,可以使用java.nio.channels.AsynchronousSocketChannel来实现异步I/O操作。

4. 数据库性能优化

Java应用中的数据库访问往往是性能瓶颈的根源。优化数据库访问可以减少响应时间,提升应用性能。

4.1 使用数据库连接池

每次建立新的数据库连接会消耗大量的时间和资源。使用数据库连接池(如HikariCP、C3P0等)可以复用数据库连接,减少连接创建和销毁的开销。数据库连接池通过维护一个连接池,在应用程序需要访问数据库时,直接从池中获取连接,使用完毕后再归还到池中。

4.2 优化SQL查询

复杂的SQL查询可能会导致数据库性能瓶颈,影响Java应用的响应速度。以下是优化SQL查询的几个常见方法:

  • 使用索引:确保数据库表中的常用查询字段添加索引,以提高查询效率。
  • 减少不必要的查询:避免每次查询都从数据库中获取大量的数据,只查询需要的字段。
  • 优化查询语句:避免使用低效的查询语句,使用分页查询来减少一次查询的数据量。
4.3 缓存优化

使用缓存可以显著减少数据库的访问压力,提升性能。常见的缓存方案有:

  • 内存缓存:如使用ConcurrentHashMap等数据结构,存储频繁访问的数据。
  • 分布式缓存:如Redis、Memcached等,可以将缓存分布在多个节点上,提供更高的吞吐量。
5. 代码优化

除了JVM配置、线程管理和I/O优化外,代码本身的优化也是提高Java性能的关键。以下是一些常见的代码优化技巧:

  • 减少对象创建:频繁的对象创建和销毁会增加内存负担和GC的压力。可以通过对象池、缓存等方式来复用对象。
  • 使用StringBuilder替代字符串拼接:在循环中拼接字符串时,StringBuilder比直接使用+操作符更加高效。
  • 避免不必要的同步:在多线程环境中,过度的同步会导致性能瓶颈。可以通过减少同步的范围,或使用java.util.concurrent包中的并发工具类来优化。

Java性能调优是一个多维度的过程,涉及JVM内存管理、垃圾回收、线程管理、I/O优化、数据库优化等多个方面。通过合理配置JVM参数、选择合适的垃圾回收器、优化多线程和I/O操作、减少数据库访问瓶颈,开发者可以有效提升Java应用程序的性能。性能调优不仅是技术的挑战,更是应用架构设计的一部分,只有从全局出发,才能真正解决性能瓶颈,构建高效、稳定的Java系统。

四、总结

Java性能调优是一个涉及多方面的过程,包括对JVM底层机制的理解、对内存管理和垃圾回收的优化、对代码执行效率的提升以及对I/O、数据库等系统层面的调优。通过深入了解JVM的内存模型、垃圾回收机制和JIT编译机制,结合实际的调优工具与策略,可以大大提升Java应用程序的性能。

性能调优并不是一蹴而就的过程,需要不断监控、分析和迭代优化。在现代复杂的Java应用中,掌握这些底层知识并灵活运用,将为开发者提供无穷的潜力,帮助解决应用性能瓶颈,确保系统的高效、稳定运行。

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

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

相关文章

odo18实施——销售-仓库-采购-制造-制造外包-整个流程自动化单据功能的演示教程

安装模块 安装销售 、库存、采购、制造模块 2.开启外包功能 在进入制造应用点击 配置—>设置 勾选外包&#xff0c;点击保存 添加信息 一、添加客户信息 点击到销售应用 点击订单—>客户 点击新建 创建客户1&#xff0c;及其他客户相关信息&#xff0c;点…

Logo语言的在线课程学习

Logo语言在线课程学习的探索 引言 在信息技术快速发展的今天&#xff0c;编程已经成为一门重要的技能。尤其随着人工智能、数据分析和互联网技术的普及&#xff0c;各种编程语言层出不穷&#xff0c;其中Logo语言以其独特的教育意义和学习优势&#xff0c;逐渐受到学校和教育…

情感语音的“开源先锋”!网易开源

语音合成技术近年来取得了显著进步&#xff0c;特别是在语音克隆、语音助手、配音服务和有声读物等领域。然而&#xff0c;如何让合成的语音更具情感&#xff0c;更贴近人类的真实表达&#xff0c;一直是这一领域的重要研究方向。今天&#xff0c;我们将为大家介绍一款由网易有…

摄像头模块对焦方式的类型

摄像头模块的对焦方式直接影响成像清晰度和使用场景适应性&#xff0c;不同技术各有其优缺点。以下是常见对焦方式及其原理、特点和应用场景的详细说明&#xff1a; ‌1. 固定对焦&#xff08;Fixed Focus&#xff09;‌ ‌原理‌&#xff1a;镜头固定在特定距离&#xff08;…

使用Vue、Nodejs以及websocket搭建一个简易聊天室

简易聊天室 说在前面效果展示websocketwebsocket的由来websocket的特点 vue前端静态结构效果代码 点击切换用户以及该用户高亮实现思路效果展示 发送消息功能效果展示 连接服务端 Nodejs服务器端实现步骤代码 说在前面 在学习计算机网络的时候&#xff0c;看到了websocket这个…

【免费】2005-2019年各地级市绿色专利申请量数据

2005-2019年各地级市绿色专利申请量数据 1、时间2005-2019年 2、来源&#xff1a;国家知识产权局 3、指标&#xff1a;省份、城市、年份、绿色发明专利申请量、绿色实用新型专利申请量 4、范围&#xff1a;360地级市 5、指标解释&#xff1a;绿色专利是指涉及环保、新能源…

架构师面试(二十六):系统拆分

问题 今天我们聊电商系统实际业务场景的问题&#xff0c;考查对业务系统问题的分析能力、解决问题的能力和对系统长期发展的整体规划能力。 一电商平台在早期阶段业务发展迅速&#xff0c;DAU在 10W&#xff1b;整个电商系统按水平分层架构进行设计&#xff0c;包括【入口网关…

2. Qt界面文件原理

本节主要介绍ui文件如何与窗口关联&#xff0c;并通过隐式连接方式显示对话框 本文部分ppt、视频截图原链接&#xff1a;[萌马工作室的个人空间-萌马工作室个人主页-哔哩哔哩视频] 1 UI文件如何与窗口关联 1.1 mainwindow.cpp的头文件ui_mainwindow.h 根据编译原理的基本规…

雅思大作文写作——词伙、简单句、并列句的使用

词伙是一些可以表达我们常用观点的单词组合,这个组合可能不只是2-3个单词,也可能是很多单词组成的一个短句。 一、词伙使用 1. 不要中译英 2. 重视词伙,而非单词 如何替换表达 1. 如果要替换的是一个名词,如students,则有下面的一些方法: A. 使用替换词或者词组:y…

⭐算法OJ⭐滑动窗口最大值【双端队列(deque)】Sliding Window Maximum

文章目录 双端队列(deque)详解基本特性常用操作1. 构造和初始化2. 元素访问3. 修改操作4. 容量操作 性能特点时间复杂度&#xff1a;空间复杂度&#xff1a; 滑动窗口最大值题目描述方法思路解决代码 双端队列(deque)详解 双端队列(deque&#xff0c;全称double-ended queue)是…

电机的了解到调试全方面讲解

一、什么是电机 电机是一种将电能转换为机械能的装置,通常由定子、转子和电磁场组成。 当电流通过电机的绕组时,产生的磁场会与电机中的磁场相互作用,从而使电机产生旋转运动。电机广泛应用于各种机械设备和工业生产中,是现代社会不可或缺的重要设备之一。 常见的电机种…

分布式微服务系统架构第97集:JVM底层原理

加群联系作者vx&#xff1a;xiaoda0423 仓库地址&#xff1a;https://webvueblog.github.io/JavaPlusDoc/ https://1024bat.cn/ JVM 内存结构 Java 虚拟机的内存空间分为 5 个部分&#xff1a; 程序计数器 Java 虚拟机栈 本地方法栈 堆 方法区 JDK 1.8 同 JDK 1.7 比&…

制定大运维管理体系的标准、流程、机制、规范

规划并制定大运维管理体系的标准、流程、机制、规范&#xff0c;对于确保平台的可用性和稳定性至关重要。这一过程涉及从顶层设计到具体执行的全面考量&#xff0c;需要综合考虑业务需求、技术架构、团队能力等多方面因素。以下是一个基本框架&#xff0c;用于指导如何构建有效…

TruPlasma RF 3006 软件TRUMPF HUETTINGER TRUPLASMA RF 3006 调试监控软件

TruPlasma RF 3006 软件TRUMPF HUETTINGER TRUPLASMA RF 3006 调试监控软件

第16届蓝桥杯单片机模拟试题Ⅱ

试题 代码 sys.h #ifndef __SYS_H__ #define __SYS_H__#include <STC15F2K60S2.H> //ds1302.c extern unsigned char time[3]; void w_ds1302(); void r_ds1302(); //iic.c float v_adc(unsigned char addr); //sys.c extern float light_v; extern float rb2_v; exte…

清华《数据挖掘算法与应用》FP-Growth算法

【例 8.7】实现FP 树算法,并对模拟数据集 simpDat挖掘频繁项集,最小支持度为2,绘制 FP树并输出频繁项集。 运行结果&#xff1a; 声明&#xff1a;著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 # -*- coding: utf-8 -*- ""&q…

npm 项目命名规则

以下是 npm 项目命名规则的详细说明&#xff1a; 一、核心命名规则 必须使用小写字母 名称中不能包含大写字母。原因&#xff1a; 跨平台兼容性&#xff08;如 Linux 区分大小写&#xff0c;而 Windows 不区分&#xff09;。避免命令行和 URL 中的大小写冲突&#xff08;例如包…

Ubertool 的详细介绍、安装指南及使用说明

Ubertool&#xff1a;多协议网络分析与调试平台 一、Ubertool 简介 Ubertool 是一款开源的 多协议网络分析工具&#xff0c;专为物联网&#xff08;IoT&#xff09;、嵌入式系统和工业自动化领域设计。它支持蓝牙、Wi-Fi、LoRa、CAN总线等多种通信协议的实时监控、数据包捕获…

AI重构农业:从“面朝黄土“到“数字原野“的产业跃迁—读中共中央 国务院印发《加快建设农业强国规划(2024-2035年)》

在东北黑土地的万亩良田上&#xff0c;无人机编队正在执行精准施肥作业&#xff1b;在山东寿光的智慧大棚里&#xff0c;传感器网络实时调控着番茄生长的微环境&#xff1b;在云南的咖啡种植园中&#xff0c;区块链溯源系统记录着每粒咖啡豆的旅程。这场静默的农业革命&#xf…

FogFL: Fog-Assisted Federated Learning for Resource-Constrained IoT Devices

摘要 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 -在本文中&#xff0c;我们提出了一个支持雾的联邦学习框架–FogFL–来促进资源受限的物联网环境中延迟敏感应用的分布式学习。联邦学习&#xff08;FL&#xff09;是一种流行的分…