JVM生产环境问题定位与解决实战(三):揭秘Java飞行记录器(JFR)的强大功能
提到飞行记录器,或许你的脑海中并未立刻浮现出清晰的画面,但一说起“黑匣子”,想必大多数人都能恍然大悟,知晓其重要性及用途。在航空领域,黑匣子作为不可或缺的设备,默默记录着飞行过程中的每一项关键数据,从飞行高度、速度到机舱内的对话,无一遗漏。一旦飞机发生事故,这些珍贵的数据便成为调查人员还原事件真相、精准定位事故原因的宝贵线索。
同样地,在软件开发的世界里,也有这样一个“黑匣子”般的存在——Java飞行记录器(Java Flight Recorder,简称JFR)。它借鉴了航空黑匣子的设计理念,却应用于一个截然不同的领域:Java应用程序的性能分析与故障排查。
一、 背景与概述
1.1 JFR 简介
Java Flight Recorder (JFR) 是 Oracle JDK 内置的性能分析工具,用于监控 JVM 和 Java 应用程序的运行时行为。其特点包括:
- 低开销:生产环境中通常仅产生
1%左右的性能损耗 - 实时监控:可记录 JVM 事件、方法调用、内存分配等详细信息、支持动态启停记录
- 事件驱动:捕获超过 200 种不同类型的事件(JDK 11+)
- 集成分析:与 Java Mission Control (JMC) 工具深度集成
Java飞行记录器(Java Flight Recorder,JFR)是JVM内置的低开销性能分析和故障排查工具,用于记录Java应用程序运行时的详细数据,类似飞机的“黑匣子”。它通过事件机制采集JVM和应用程序的运行时信息,包括CPU、内存、线程、垃圾回收(GC)、锁竞争等数据,帮助开发者定位性能瓶颈和异常问题。
📌 适用场景:性能调优、内存泄漏排查、高 CPU 使用率分析等
1.2. JFR 的发展历史
1.2.1. 关键里程碑
- JRockit Flight Recorder:JFR 最初是由 BEA Systems 开发的 JRockit JVM的一部分,当时被称为 JRockit Flight Recorder。
- Oracle 收购 Sun Microsystems:随着 Oracle 收购了 Sun Microsystems(Java的原始开发者)以及 BEA Systems,JFR 被集成到了 HotSpot JVM 中,并从 JDK 7u40 和 JDK 8u40开始被包含进去。此时,JFR 还是一个商业特性,需要许可证才能在生产环境中使用。
- JDK 11:JFR 2.0版本发布,提供了更丰富的功能集。JFR 成为了 OpenJDK 的一部分,无需额外安装。作为一个开源项目,不再需要商业许可证即可使用。
- JDK 14:引入了 JFR Event Streaming,允许实时处理 JFR 事件。
- JDK 17:稳定支持虚拟线程事件,并增强云原生环境兼容性。
1.2.2. Java Flight Recorder (JFR) 版本变化
| JDK版本 | 发布日期 | 主要变化与新特性 |
|---|---|---|
| JDK 7u40 | 2013年9月 | - JFR首次在Oracle JDK中作为商业特性引入 - 提供基本的事件记录功能,如GC、线程等 - JCMD控制 |
| JDK 8u40 | 2015年3月 | - 增加了更多的内置事件类型 - 改善了性能开销,减少了对应用程序的影响 -JMX动态控制 |
| JDK 9 | 2017年9月 | - 开始支持自定义事件 - 引入了更丰富的API用于编程控制JFR会话 |
| JDK 11 | 2018年9月 | - JFR成为OpenJDK的一部分(JEP 328) - JFR 2.0 版本、完全开源,社区可以贡献代码 - 支持JIT编译器事件,记录编译器活动和性能数据 - 对容器环境的支持,更好地适应Docker等容器化部署 - 改进了数据格式和压缩算法,提高了存储效率 |
| JDK 13 | 2019年9月 | - 引入了jdk.jfr.consumer模块,允许程序化地读取和分析JFR文件- 增强了事件过滤和配置选项 |
| JDK 14 | 2020年3月 | - 添加了对虚拟线程的支持(实验性) - 改进了事件元数据的可读性和灵活性 |
| JDK 15 | 2020年9月 | - 引入了新的事件类别,如jdk.VirtualThread*- 改进了JFR与容器环境的兼容性 |
| JDK 16 | 2021年3月 | - 支持动态调整采样率 - 增强了对云原生环境的支持 |
| JDK 17 | 2021年9月 | - 稳定版支持虚拟线程事件 - 改进了与Kubernetes等平台的集成 - 增强了安全性,包括对敏感数据的保护 |
| JDK 18 | 2022年3月 | - 引入了对GraalVM Native Image的支持 - 改进了内存管理和垃圾回收事件的详细程度 |
| JDK 19 | 2022年9月 | - 增强了对多租户环境的支持 - 改进了事件的时间戳精度 |
| JDK 20 | 2023年3月 | - 引入了新的事件类型,如jdk.CodeCacheFlush- 改进了对异步事件的支持 |
| JDK 21 | 2023年9月 | - 进一步增强了对虚拟线程的支持 - 改进了与Spring Boot等框架的集成 |
二、启用 JFR
2.1. 通过命令行参数启动
# JDK 8 需要添加以下参数,解锁商业功能
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder ...# JDK 11+ 开源版本直接启用
java -XX:StartFlightRecording:delay=5s,duration=60s,name=MyRecording,filename=recording.jfr ...
常用选项:
filename=recording.jfr:指定输出文件名duration=60s:设置录制时长delay=10s:延迟启动时间settings=profile:使用预定义配置文件(如profile,default)name=MyRecording:为录制会话命名
2.2. 运行时触发,使用jcmd工具
jcmd <PID> JFR.start duration=60s filename=recording.jfr
jcmd <PID> JFR.dump filename=partial.jfr
jcmd <PID> JFR.stop
2.3. 通过JMC(JDK Mission Control)启动
操作步骤:
- 打开JMC工具。
- 连接到正在运行的JVM实例。
- 在左侧导航栏选择“Flight Recorder”。
- 配置录制设置(如持续时间、事件类型等)。
- 点击“Start Recording”。
2.4 通过Spring Boot Actuator集成启动
2.4.1. 添加依赖
在pom.xml中添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator</artifactId>
</dependency>
2.4.2. 使用HTTP接口启动
curl -X POST http://localhost:8080/actuator/jfr/start
curl -X POST http://localhost:8080/actuator/jfr/dump?filename=myapp_recording.jfr
curl -X POST http://localhost:8080/actuator/jfr/stop
三、JFR 事件
在 JFR中,一切皆为 Event!JFR 事件是 JFR 捕获和记录的最小数据单元,每个事件都代表了在特定时间点上系统或应用某个方面的信息。每条事件记录包含了多个数据字段,如时间戳、事件持续时间、以及其他与业务或系统状态相关的元数据。大部分的 Event,都有 Event 是在哪个线程发生的,Event 发生的时候这个线程的调用栈,Event 的持续时间。这就非常有用了,利用这些信息,我们可以回溯 Event 发生当时的情况。
3.1. 按来源分类
| 类别 | 说明 | 示例事件 |
|---|---|---|
| JVM 事件 | JVM 内部操作产生的事件 | jdk.GarbageCollection, jdk.JITCompilation |
| JDK 库事件 | JDK 类库(如 I/O、网络、集合)触发的事件 | jdk.FileRead, jdk.SocketWrite |
| OS 事件 | 操作系统级别的资源监控数据 | jdk.CPULoad, jdk.PhysicalMemory |
| 自定义事件 | 开发者定义的应用层事件 | com.example.OrderProcessEvent |
3.2. 按触发方式分类
- 阈值触发事件:当指标超过预设阈值时记录(如
jdk.CPULoad) - 周期采样事件:按固定时间间隔采集(如
jdk.ThreadAllocationStatistics) - 即时触发事件:特定操作发生时立即记录(如
jdk.ExceptionThrown)
3.3、关键内置事件
3.3.1. 垃圾回收相关
| 事件名称 | 作用 |
|---|---|
jdk.GarbageCollection | 记录 GC 暂停时间和原因(Young GC/Full GC) |
jdk.OldObjectSample | 跟踪可能引发内存泄漏的旧对象(需启用 -XX:StartFlightRecording=old-object-queue-size=256) |
3.3.2. 线程与锁
| 事件名称 | 作用 |
|---|---|
jdk.ThreadSleep | 记录线程睡眠时间 |
jdk.JavaMonitorWait | 监控 synchronized 锁等待时间 |
jdk.ThreadPark | 跟踪 LockSupport.park() 调用(如 AQS 锁) |
3.3.3. 异常与错误
| 事件名称 | 作用 |
|---|---|
jdk.ExceptionThrown | 记录所有异常抛出事件(包括堆栈跟踪) |
jdk.ErrorThrown | 记录严重错误事件(如 OutOfMemoryError) |
3.3.4. I/O 与网络
| 事件名称 | 作用 |
|---|---|
jdk.FileRead | 跟踪文件读取操作(包含路径和耗时) |
jdk.SocketRead | 记录 Socket 读取数据量及延迟 |
3.3.5. JIT 与类加载
| 事件名称 | 作用 |
|---|---|
jdk.JITCompilation | 记录方法编译耗时和优化级别 |
jdk.ClassLoad | 跟踪类加载过程及耗时 |
3.4. 多线程低开销设计与异步存储原理
3.4.1. 事件产生与多线程协作
- 多线程事件触发:
JFR 事件由业务线程在执行过程中主动生成(如方法调用、异常抛出、锁竞争等),每个线程独立维护线程本地缓冲区(Thread Local Buffer),直接以二进制格式缓存事件流。 - 线程隔离与无锁设计:
各线程仅操作自身缓冲区,避免全局锁竞争,确保事件记录低延迟(通常低于微秒级)。
3.4.2. 分级缓冲存储流程
-
线程本地缓冲区(Thread Local Buffer)
- 默认容量约 34KB,采用循环队列结构存储二进制事件数据。
- 缓冲区满时触发异步刷写(非阻塞),将数据批量推送至全局缓冲区。
-
全局缓冲区(Global Buffer)与持久化
- 全局缓冲区整合多线程事件流,由独立的
jfr守护线程负责管理。 - 后台线程将全局缓冲区的数据异步写入磁盘(生成
.jfr文件),完全分离业务线程与I/O操作,避免阻塞主逻辑。
- 全局缓冲区整合多线程事件流,由独立的
3.4.3. 高效性核心设计
- 二进制直接存储:
事件以二进制格式在内存中流转,跳过多余的序列化/反序列化步骤,减少 CPU 开销。 - 异步分层处理:
业务线程仅负责生成事件,缓冲区刷写与持久化由独立线程完成,通过批量合并降低 I/O 频率。 - 动态采样与可控开销:
JFR 支持按需配置采样率(如-XX:FlightRecorderOptions=stackdepth=128),通过 JVM 内部 Hook 实现非侵入式监控,无需代码插桩。
3.4.4. 自定义事件对业务的影响
- 轻量级托管机制:
开发者通过继承jdk.jfr.Event定义的事件,由 JFR 框架统一管理。调用commit()方法时,事件仅写入线程本地缓冲区,不占用业务线程额外时间。 - 背压(Backpressure)保护:
若事件产生速率超过持久化能力(如高频自定义事件),JFR 会触发背压机制,选择性丢弃低优先级事件或限制事件生成,防止资源耗尽。 - 可控的性能损耗:
合理使用自定义事件(如避免每秒超 10 万次高频提交),对业务延迟的影响通常可控制在 1%~2% 以内,极端场景需结合采样策略优化。
四、自定义事件开发
4.1. 自定义事件开发价值
通过自定义JFR事件,开发者可以:
- 业务指标可视化:记录订单创建、支付处理等关键业务指标
- 精准性能分析:追踪特定方法执行耗时、资源消耗
- 上下文关联:将JVM事件与业务逻辑关联分析
- 生产环境诊断:低开销实时监控生产系统
4.2. 自定义事件开发四部曲
4.2.1. 定义事件类
@Name("com.example.OrderCreated")
@Label("Order Created Event")
@Category("Business")
@Description("Records order creation information")
public class OrderCreatedEvent extends Event {@Label("Order ID")public String orderId;@Label("Total Amount")@Amount(Currency.CNY)public double amount;@Label("User Type")public UserType userType;@Label("Creation Duration")@Timespan(Timespan.MILLISECONDS)public long duration;
}
注解说明:
@Name: 定义事件的全局唯一标识符,推荐使用反向域名命名法(类似Java包名),避免与JVM内置事件冲突。@Label: 事件名称,在JMC等可视化工具中作为显示名称。@Category: JMC中的分类显示,在JMC左侧导航树状呈现。@Description: 提供事件的详细文档说明吗,在JMC中通过"Show Description"查看。
4.2.2. 触发事件记录
public class OrderService {public void createOrder(OrderRequest request) {OrderCreatedEvent event = new OrderCreatedEvent();if (event.isEnabled()) {long start = System.nanoTime();// 业务逻辑执行...event.orderId = generatedId;event.amount = calculateAmount();event.userType = getCurrentUserType();event.duration = (System.nanoTime() - start) / 1_000_000;event.commit();}}
}
4.2.2. 事件注册与启用
@Registered(true)
public class OrderCreatedEvent extends Event {//...
}
动态启用配置:
jcmd <PID> JFR.configure threshold=10ms stacktrace=true path-to-gc-roots=true
4.2.4. 事件数据分析
使用JMC分析:
public static void analyzeJfr(File recordingFile) throws IOException {try (RecordingStream rs = new RecordingStream(recordingFile)) {rs.onEvent("com.example.OrderCreated", event -> {System.out.printf("订单%s 金额%.2f 耗时%dms%n",event.getString("orderId"),event.getDouble("amount"),event.getLong("duration"));});rs.start();}
}
五、高级技巧
5.1 异步事件处理
@Async
public class AsyncPaymentEvent extends Event {//...
}
5.2 阈值控制
@Threshold("20 ms")
public class SlowMethodEvent extends Event {//...
}
5.3 自定义转换器
public class UserTypeConverter extends Converter<UserType> {public String toString(UserType type) {return type.name().toLowerCase();}
}public class OrderCreatedEvent extends Event {@Converter(UserTypeConverter.class)public UserType userType;
}
六、总结
通过自定义JFR事件,开发者可以获得:
- 生产环境细粒度监控能力
- 业务与JVM事件的关联分析
- 传统日志无法实现的性能洞察
建议结合JMC可视化工具和jfr命令行工具,构建完整的性能监控体系。下一篇来具体介绍使用JMC进行JFR性能分析指南。
最佳实践:从关键业务路径开始逐步增加事件埋点,通过持续的性能分析迭代优化事件配置。
相关文章:
JVM生产环境问题定位与解决实战(三):揭秘Java飞行记录器(JFR)的强大功能
提到飞行记录器,或许你的脑海中并未立刻浮现出清晰的画面,但一说起“黑匣子”,想必大多数人都能恍然大悟,知晓其重要性及用途。在航空领域,黑匣子作为不可或缺的设备,默默记录着飞行过程中的每一项关键数据…...
爬虫框架与库
爬虫框架与库是用于网络数据抓取的核心工具,帮助开发者高效地从网页中提取结构化数据。 Requests:用于发送HTTP请求。 BeautifulSoup:用于解析HTML和XML。 Scrapy:强大的爬虫框架,适合大规模爬取。 Selenium&#…...
PyTorch常用函数总结(持续更新)
本文主要记录自己在用 PyTorch复现经典模型 过程中遇到的一些函数及用法,以期对 常见PyTorch函数 更加熟练~ 官方Docs:PyTorch documentation — PyTorch 2.6 documentation 目录 数据层面 torch.sign(tensor) torch.tensor(np.eye(3)[y]) torch.on…...
代码异常(js中push)NO.4
1. 环境 Vue3,Element Plsu 2. 示例代码 const { updateBy, updateTime, ...curObj } form.valuecurObj.id props.tableData.length 1var newTableData props.tableData.push(curObj)updateTableData(newTableData)3. 情景描述 newTableData变成了整数&#…...
Anaconda 2025 最新版安装与Python环境配置指南(附官方下载链接)
一、软件定位与核心功能 Anaconda 2025 是Python/R数据科学集成开发平台,预装1500科学计算库,新增AI模型可视化调试、多环境GPU加速等特性。相较于传统Python安装,其优势包括: 环境隔离:通过conda工具实现多版本Pyth…...
Vue 中动态实现进度条
在 Vue 中动态实现进度条,基本上有两种常见的方法:直接通过 Vue 数据绑定控制样式,或者利用外部库来实现更复杂的功能。我们会深入探讨这两种方式,并且详细说明每种方法的实现步骤、优缺点以及使用场景。 1. 使用 Vue 数据绑定来…...
CSS滚动条原理与自定义样式指南,CSS滚动条样式失效,滚动条样式无效,-webkit-scrollbar无效,overflow不显示滚动条
滚动内容形成的必要条件 CSS Overflow属性解析 MDN官方文档-Overflow属性 菜鸟教程-Overflow属性 overflow 属性控制内容溢出元素框时在对应的元素区间内是否添加滚动条。 值描述visible默认值。内容不会被修剪,会呈现在元素框之外。hidden内容会被修剪…...
Three.js 入门(辅助、位移、父子关系、缩放旋转、响应式布局)
本篇主要学习内容 : 三维坐标系与辅助坐标系物体位移与父子元素物体的缩放与物体的旋转设置响应式画布与全屏控制 点赞 关注 收藏 学会了 本文使用 Three.js 的版本:171 基于 Vue3vite开发调试 1.三维坐标系与辅助坐标系 1.1) 导入three和轨道控制器 // 导入…...
python算法-用递归打印数字3的幂--Day017
文章目录 前言采用创新方式,精选趣味、实用性强的例子,从不同难度、不同算法、不同类型和不同数据结构进行总结,全面提升算法能力。例1.用递归打印数字例2.相对排名 总结 前言 采用创新方式,精选趣味、实用性强的例子,…...
Selenium 与 Coze 集成
涵盖两者的基本概念、集成步骤、代码示例以及相关注意事项。 基本概念 Selenium:是一个用于自动化浏览器操作的工具集,支持多种浏览器(如 Chrome、Firefox 等),能够模拟用户在浏览器中的各种操作,如点击、输入文本、选择下拉框等,常用于 Web 应用的自动化测试。Coze:它…...
AWS CLI将读取器实例添加到Amazon Aurora集群
Amazon Aurora是AWS提供的一种兼容MySQL和PostgreSQL的关系数据库服务。Aurora集群由一个写入器实例和多个读取器实例组成,可以提供高可用性、高性能和可扩展性。在本文中,我们将介绍如何使用AWS命令行界面(CLI)将读取器实例添加到现有的Aurora集群中。 © ivwdcwso (ID: u…...
NTS库学习,找bug中......
基础知识 Coordinate: 表示一个二维坐标点,包括 X 和 Y 坐标值。 CoordinateSequence: 由一系列 Coordinate 对象组成的序列,可以表示线、多边形等几何对象的顶点。 CoordinateFilter: 用于对几何对象的坐标进行过滤或修改的接口。 Geometry: 表示一个几…...
五十天精通硬件设计第40天-硬件测试流程
目录 一、硬件测试流程概述 二、详细测试流程 1. 需求分析与测试计划 2. 测试环境搭建 3. 测试执行 3.1 基本功能测试 3.2 性能测试 3.3 环境与可靠性测试 3.4 安全与合规性测试 4. 问题分析与调试 5. 回归测试与报告输出 三、关键注意事项 四、常见问题与解决 五…...
R语言安装教程(附安装包)R语言4.3.2版本安装教程
文章目录 前言一、安装包下载二、R-4.3.2安装步骤三、rtools43安装步骤四、RStudio安装步骤 前言 本教程将详细、全面地为你介绍在 Windows 系统下安装 R 语言 4.3.2 的具体步骤。无论你是初涉数据领域的新手,还是希望更新知识体系的专业人士,只要按照本…...
数据库 安装initializing database不通过
出现一下情况时: 处理方法: 将自己的电脑名称 中文改成英文 即可通过...
自动驾驶两个传感器之间的坐标系转换
有两种方式可以实现两个坐标系的转换。 车身坐标系下一个点p_car,需要转换到相机坐标系下,旋转矩阵R_car2Cam,平移矩阵T_car2Cam。点p_car在相机坐标系下记p_cam. 方法1:先旋转再平移 p_cam T_car2Cam * p_car T_car2Cam 需要注…...
信号——进程间通信(20250225)
1. 信号 管道:进程间数据通信(同步通信) 信号:进程间通信,用来发送通知(异步通信,中断) 1)同步通信:发送端和接收端,使用同一时钟通信 异步通信:发送端和接收端使用不同时钟通信 …...
transformer架构嵌入层位置编码之动态NTK-aware位置编码
前文,我们已经构建了一个小型的字符级语言模型,是在transformer架构基础上实现的最基本的模型,我们肯定是希望对该模型进行改进和完善的。所以我们的另外一篇文章也从数据预处理、模型架构、训练策略、评估方法、代码结构、错误处理、性能优化等多个方面提出具体的改进点,但…...
东信营销科技巨额补贴仍由盈转亏:毛利率大幅下滑,现金流告急
《港湾商业观察》施子夫 近期,东信营销科技有限公司(以下简称,东信营销科技)递表港交所,联席保荐机构为海通国际和中银国际。 东信营销科技的国内运营主体为深圳市东信时代信息技术有限公司。尽管期内收入规模有所提…...
[电感、磁珠、0欧姆电阻]的区别与应用特性
1. 电感(Inductor) 基础特性: 储能元件:通过磁场存储能量,阻碍电流突变()。 核心参数:电感值(L)、额定电流、直流电阻(DCR)、自谐振频率(SRF)。 频率特性:感抗 ,(通直流、阻交流),低频时阻抗低,高频时阻抗高(但受SRF限制)。 电路符号及实物:多为绕线结…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
