Java虚拟线程惰性加载机制剖析
Java虚拟线程惰性加载机制剖析前言Java虚拟线程惰性加载机制1. 物理栈结构与 HotSpot 数据模型切片HotSpot 核心数据结构差异表2. Continuation 挂起机制 (continuationFreezeThaw.cpp) 源码剖析JNI Pinning 机制的 C 源码实现Panama Trivial Downcall 为何完全避免 Pinning3. Safepoint 状态机与 Stub 机器码生成对比1. 传统 JNI Downcall 汇编 Stub 生成逻辑 (sharedRuntime_x86_64.cpp)2. Panama Trivial Downcall 汇编生成逻辑 (downcallLinker.cpp)汇编指令级别的真实差异对比4. Carrier 线程调度器 (ForkJoinPool) 运行状态模型演进破坏契约的致命陷阱Trivial Call 阻塞与 GC 死锁5. 源码与架构对比总结矩阵前言本文旨在记录近期研读Java源码的学习心得与疑难问题。由于个人理解水平有限文中内容难免存在疏漏恳请读者不吝指正。Java虚拟线程惰性加载机制1. 物理栈结构与 HotSpot 数据模型切片虚拟线程java.lang.VirtualThread的调度核心是基于 JVM 内部的jdk.internal.vm.Continuation实现。当虚拟线程在 Carrier 线程ForkJoinWorkerThread上运行时其 Java 栈帧直接生长在 Carrier 线程的 OS 物理栈上。在调用底层 Native 代码时传统 JNI 与 Panama Trivial Downcall 建立了完全不同的物理栈拓扑与 HotSpot 数据模型 1. 传统 JNI Downcall 物理栈拓扑与 Anchor 状态 [ Physical OS Stack ] [ HotSpot JavaThread / Thread Anchor ] --------------------------------------------------- | Native C/C Frame (e.g., read(), pthread_wait) | ◄─ OS Native Stack Pointer (RSP) --------------------------------------------------- | JNI Stub Frame (Generated by SharedRuntime) | | - Saved JNIHandleBlock | | - Saved Preserved Registers | | - Transition: _thread_in_Java - _thread_in_nat | --------------------------------------------------- ◄─ JavaFrameAnchor::_last_Java_sp | Java Compiled Frame (Method calling JNI) | --------------------------------------------------- | ContinuationEntry Frame | ◄─ Continuation Boundary --------------------------------------------------- | Carrier OS Frame (ForkJoinWorkerThread) | --------------------------------------------------- 2. Panama Trivial Downcall 物理栈拓扑 [ Physical OS Stack ] [ HotSpot JavaThread / Thread Anchor ] --------------------------------------------------- | Native C Function (Direct C Call, e.g., getpid) | ◄─ RSP (Directly executing Native PC) --------------------------------------------------- | C2 NMethod Frame (Direct Call Site) | ◄─ JavaFrameAnchor Unchanged | - Inline-mapped native register ABI | | - State stays _thread_in_Java | --------------------------------------------------- | ContinuationEntry Frame | ◄─ Continuation Boundary --------------------------------------------------- | Carrier OS Frame (ForkJoinWorkerThread) | ---------------------------------------------------HotSpot 核心数据结构差异表数据结构/字段 (JavaThread)传统 JNI DowncallPanama Trivial Downcall_thread_state强行切换为_thread_in_native**保持_thread_in_Java**_anchor._last_Java_sp显式刷新并锚定用于 GC 栈扫描不设置/不刷新被当作纯 Java 代码_active_handles挂载JNIHandleBlock分配 Local Ref不分配零 JNI 句柄开销_continuation指向当前Continuation但处于 Pinned 阻断指向当前Continuation完全透明2. Continuation 挂起机制 (continuationFreezeThaw.cpp) 源码剖析当虚拟线程需要被挂起如调用VirtualThread.park()或非阻塞 I/O 等待时HotSpot 会触发Continuation.yield()进而调用 HotSpot 运行时 C 代码Freeze::freeze()。该过程尝试将物理栈上的 Java 栈帧打包拷贝到 Java 堆内的stackChunkOop对象中。JNI Pinning 机制的 C 源码实现在 HotSpot 源码src/hotspot/share/runtime/continuationFreezeThaw.cpp中Freeze引擎在遍历栈帧时会严格检查当前栈帧的属性// 源码位置: src/hotspot/share/runtime/continuationFreezeThaw.cpptemplatetypenameConfigclassFreeze:publicStackObj{// ...// 检查指定栈帧是否允许进行 Freeze (解冻/打包到堆)inlineFreeze::CanFreezecan_freeze_frame(constframefr,constRegisterMap*map){// 1. 如果检测到当前栈帧是 JNI Native 栈帧或 JNI Stub 帧if(fr.is_native_frame()||fr.is_entry_frame()){// 记录 Pinning 原因包含了 Native 栈帧绝对无法剥离event_log(Pinned due to native frame: spINTPTR_FORMAT,p2i(fr.sp()));returnCanFreeze::PIN_NATIVE_FRAME;}// 2. 检查 JNI 临界区 (Critical Section)if(_thread-jni_environment()-has_critical_scavenge_handshake()){returnCanFreeze::PIN_JNI_CRITICAL;}returnCanFreeze::CAN_FREEZE;}// Freeze 递归压栈主循环inlineCanFreezerecurse_freeze(framefr,framecaller){CanFreeze can_freezecan_freeze_frame(fr,_map);if(can_freeze!CanFreeze::CAN_FREEZE){// 一旦遇到无法 Freeze 的帧立刻中止栈拷贝并将 Continuation 标记为 Pinned_cont.set_pinned(can_freeze);returncan_freeze;}// 只有纯 Java 帧 (Compiled NMethod / Interpreted) 才能执行字节流拷贝至 stackChunkOopcopy_frame_to_chunk(fr);returnrecurse_freeze(caller,...);}};解析传统 JNI 在执行时物理栈上存在由 C/C 编译器生成的机器码帧Native Frame。这些帧包含真实的物理寄存器入栈记录、C 语言 ABI 的栈帧指针RBP/RSP以及未由 HotSpotOopMap跟踪的裸指针Raw Pointers。当Freeze::can_freeze_frame扫描到fr.is_native_frame()时JVM 无法精准识别这些 Native 帧中的 GC Root更无法将非固定大小的 C 栈平移复制到stackChunkOop。因此_cont.set_pinned(PIN_NATIVE_FRAME)被触发彻底阻止了虚拟线程与其 Carrier 线程的解绑定Unmount。Panama Trivial Downcall 为何完全避免 Pinning在使用 Panama FFM API 并指定Linker.Option.isTrivial()时// 源码位置: src/hotspot/share/prims/universalUpcallHandler.cpp / downcallLinker.cppboolDowncallLinker::is_trivial_call(constFunctionDescriptordesc,constLinker::OptionImploptions){// Trivial Call 必须保证// 1. 极其短暂数十纳秒内完成// 2. 绝不阻塞 (Non-blocking)// 3. 绝不回调 Java (No Upcall / Java Callback)returnoptions.is_trivial();}由于isTrivial契约约束HotSpot 采取了以下执行策略不生成任何 JNI 转换帧C2 编译器将该 Downcall 视同为一条原生的汇编call指令直接编译进当前的NMethod机器码中。不允许在 Trivial Call 期间发生 Yield由于 Trivial Call 必须是非阻塞的它绝不会在 Native 函数内部触发VirtualThread.park()或任何会导致Continuation.yield()的操作。完全透明的栈结构当该 Native 函数执行完成返回后物理栈上只剩下纯净的 Java JIT 编译帧NMethod Frame。若此后该 Java 代码触发park()Freeze引擎扫描栈帧时完全看不到任何 Native Frame可以成功将栈帧打包至stackChunkOop。3. Safepoint 状态机与 Stub 机器码生成对比HotSpot JVM 的 GC 和线程管理高度依赖Safepoint安全点机制。传统 JNI 与 Panama Trivial 在 Safepoint 响应以及汇编 Stub 的生成逻辑上存在本质差异。1. 传统 JNI Downcall 汇编 Stub 生成逻辑 (sharedRuntime_x86_64.cpp)HotSpot 的 JNI Wrapper Stub 必须处理线程状态转换及 Safepoint Poll。// 源码位置: src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp// 函数: SharedRuntime::generate_native_wrappernmethod*SharedRuntime::generate_native_wrapper(MacroAssembler*masm,...){// ------------------------------------------------------------------// [步骤 1] 压入 JavaFrameAnchor保存 Java 物理栈顶指针// ------------------------------------------------------------------__movptr(Address(r15_thread,JavaThread::last_Java_sp_offset()),rsp);// ------------------------------------------------------------------// [步骤 2] 修改线程状态: _thread_in_Java - _thread_in_native// ------------------------------------------------------------------__movl(Address(r15_thread,JavaThread::thread_state_offset()),_thread_in_native);// ------------------------------------------------------------------// [步骤 3] 执行真正的 Native C 函数调用// ------------------------------------------------------------------__call(native_func_address);// ------------------------------------------------------------------// [步骤 4] 尝试切回 Java 状态: _thread_in_native - _thread_in_native_trans// ------------------------------------------------------------------__movl(Address(r15_thread,JavaThread::thread_state_offset()),_thread_in_native_trans);// 必须插入内存屏障确保线程状态修改对 GC 线程可见if(os::is_MP()){__mfence();}// ------------------------------------------------------------------// [步骤 5] 关键 Safepoint 检查 (Safepoint Poll)// ------------------------------------------------------------------Label L_safepoint_poll,L_safepoint_poll_done;// 检查 JVM 的全局 Safepoint 状态 (SafepointMechanism)__cmp32(Address(r15_thread,JavaThread::polling_word_offset()),0);__jcc(Assembler::notZero,L_safepoint_poll);__bind(L_safepoint_poll);// 如果 JVM 当前正处于 STW (Stop-The-World) 阶段阻断当前 Carrier 线程并挂起__call(RuntimeAddress(StubRoutines::forward_exception_entry()));__bind(L_safepoint_poll_done);// 恢复状态为 _thread_in_Java__movl(Address(r15_thread,JavaThread::thread_state_offset()),_thread_in_Java);__ret(0);}2. Panama Trivial Downcall 汇编生成逻辑 (downcallLinker.cpp)对于指定了Linker.Option.isTrivial()的 DowncallC2 编译器和 Foreign Linker 会完全剥离上述所有状态转换和 Safepoint Poll 代码// 源码位置: src/hotspot/share/prims/downcallLinker.cppvoidDowncallLinker::emit_fallback_stubs(...){// 当 isTrivial true 时// 1. 跳过 generate_thread_state_transition() - 不写 thread_state 内存屏障// 2. 跳过 JavaFrameAnchor 挂载// 3. 跳过 SafepointPoll Page 检查指令 (test / cmp)// 生成的汇编仅包含最原始的 C ABI 寄存器映射与 call 指令// mov rdi, arg1 (传递参数)// mov rsi, arg2// call native_function_address (直接跳转)// (返回后直接继续执行后续 Java 字节码)}汇编指令级别的真实差异对比; ; 传统 JNI Native Wrapper (以 x86_64 为例共约 15-20 条开销指令) ; mov [r150x318], rsp ; 1. 保存 JavaFrameAnchor last_Java_sp mov dword ptr [r150x300], 0x6; 2. thread_state _thread_in_native mfence ; 3. 内存屏障 call rax ; 4. 调用 C 函数 (如 clock_gettime) mov dword ptr [r150x300], 0x7; 5. thread_state _thread_in_native_trans mfence ; 6. 内存屏障 mov rax, [rip0x2100] ; 7. 读取 Safepoint Polling Page test eax, [rax] ; 8. 触发 Safepoint 条件检查 (可能导致线程挂起) jne L_safepoint_handler ; 9. 条件跳转到 Safepoint 挂起逻辑 mov dword ptr [r150x300], 0x2; 10. thread_state _thread_in_Java ; ; Panama Trivial Downcall 编译后的汇编 (C2 编译器直接内联) ; mov rdi, r12 ; 1. 寄存器参数对齐 (C ABI) call rax ; 2. 直接调用 C 函数 ; (零状态转换零 Safepoint Poll零 内存屏障开销仅为纯 call 指令的 1-2 ns)4. Carrier 线程调度器 (ForkJoinPool) 运行状态模型演进虚拟线程在 Java 层面的调度器是一个专门配置的ForkJoinPool。结合上述 HotSpot 源码分析当虚拟线程执行两类 Native 调用时ForkJoinPool的 Worker 线程Carrier将经历截然不同的状态迁移 1. 传统 JNI Downcall 场景下的 Carrier 线程状态迁移 ----------------------- | VirtualThread Run | | (State: RUNNING) | -----------┬----------- │ ▼ JNI Downcall (Thread State - _thread_in_native) ----------------------- | Exec Native Code | ◄─── 若此时 Native 代码阻塞 (如 Socket Read) -----------┬----------- │ ▼ VirtualThread 尝试 park() / yield() ----------------------- | Freeze::can_freeze() | | Returns PINNED! | ◄─── 检测到 JNI Native Frame拒绝卸载 -----------┬----------- │ ▼ ----------------------- | Carrier Pinning 发生 | ◄─── Carrier 线程 (ForkJoinWorker) 被同步强行阻塞 | (ForkJoinPool 耗尽) | 必须等待 Native Call 返回才能继续服务其他 VirtualThread ----------------------- 2. Panama Trivial Downcall 场景下的 Carrier 线程状态迁移 ----------------------- | VirtualThread Run | | (State: RUNNING) | -----------┬----------- │ ▼ Panama Trivial Downcall (Thread State 保持 _thread_in_Java) ----------------------- | Direct CPU Exec | ◄─── 极其短暂 (无 Safepoint Poll / 无状态转换) -----------┬----------- │ ▼ Native 函数瞬间执行完毕继续执行后续 Java 代码 ----------------------- | Java I/O / Park() | -----------┬----------- │ ▼ VirtualThread.park() ----------------------- | Freeze::can_freeze() | | Returns CAN_FREEZE! | ◄─── 物理栈上只有纯编译 Java 帧成功打包至 stackChunkOop -----------┬----------- │ ▼ ----------------------- | Carrier Unmounted | ◄─── Carrier 线程立刻释放零阻塞地被 ForkJoinPool 调度去执行 | (完全无缝调度) | 其他就绪的 VirtualThread -----------------------破坏契约的致命陷阱Trivial Call 阻塞与 GC 死锁当开发者在 Panama FFM 中对一个耗时长或阻塞式的 Native 函数错误地标记了Linker.Option.isTrivial()时会导致严重的 JVM 系统级故障开发者错误标记 isTrivial() 的阻塞式 Native Call │ ▼ Thread State 依然显示为 _thread_in_Java (JVM 误以为该线程正在安全地执行 Java 机器码) │ ▼ Native Call 进入长时间阻塞 (如等待 C 层的 pthread_mutex_lock) │ ▼ JVM 发起 GC试图进入 Stop-The-World (STW) 阶段 │ ▼ Safepoint 引擎等待所有 _thread_in_Java 线程到达 Safepoint Poll 点 │ ▼ 【致命死锁】由于 isTrivial 剥离了 Safepoint Poll 指令当前 Carrier 线程既不在 Safepoint 又阻塞在 Native 内部无法推进到下一个 Safepoint Poll 点 │ ▼ 整个 JVM 的 GC 线程无限期挂起等待JVM 进程彻底死锁 (STW Freeze/Deadlock)5. 源码与架构对比总结矩阵系统层级评估维度传统 JNI DowncallPanama Trivial Downcall (Linker.Option.isTrivial())HotSpot 源码入口SharedRuntime::generate_native_wrapperDowncallLinker::make_downcall_stub物理栈结构包含显式 JNI Transition Frame 与 C Native Frame无 Stub 隔离直接编译进 C2 NMethod 帧JavaThread::_thread_state_thread_in_Java→ \rightarrow→_thread_in_native→ \rightarrow→_thread_in_JavaJavaFrameAnchor必须刷入last_Java_sp记录物理栈顶完全无需更新Safepoint Poll 机制Native 返回时强行触发test eax, [safepoint_poll_page]完全剥离 (Zero Safepoint Overhead)Continuation Freeze行为触发PIN_NATIVE_FRAME强制拦截卸载完全透明 (CAN_FREEZE)Carrier 线程状态遭遇阻塞时发生 Pinning导致ForkJoinPool线程被锁死极速执行无阻塞栈帧正常解绑Carrier 被无缝复用单次 Downcall 额外开销~15 - 25 ns写屏障、状态转换、 Safepoint 检查~1 - 2 ns仅保留 CPU 硬件级的call指令开销安全与容错边界绝对安全允许 Native 阻塞GC 可穿透 Native 异步执行极高风险若误用阻塞函数会导致 JVM STW 死锁

相关新闻

Linux下RAR文件处理全攻略:从安装到实战排错

Linux下RAR文件处理全攻略:从安装到实战排错

1. 从一次文件传输的“事故”说起前几天,一个做设计的朋友火急火燎地找我,说客户发来一个巨大的素材包,后缀是.rar,他在自己的 Mac 上折腾了半天,用系统自带的归档工具打不开,下了几个免费软件也报错&#…

2026/8/18 6:57:00 阅读更多 →
西门子S7-1200 PLC定时器深度解析:从核心原理到实战应用

西门子S7-1200 PLC定时器深度解析:从核心原理到实战应用

1. 项目概述:从“定时”到“控制”的逻辑跃迁 在工业自动化领域,尤其是西门子S7-1200 PLC的编程实践中,定时器(Timer)远不止是一个简单的延时工具。它更像是一个逻辑时序的“节拍器”,是构建复杂控制逻辑、…

2026/8/18 22:04:52 阅读更多 →
PHP代码审计实战:从伪协议到preg_replace /e修饰符的CTF漏洞利用

PHP代码审计实战:从伪协议到preg_replace /e修饰符的CTF漏洞利用

1. 题目初探与环境搭建拿到这道“[BJDCTF2020]ZJCTF,不过如此1”,一看就是典型的CTF Web题目。这类题目通常不会上来就给你一个复杂的漏洞链,而是考验你对PHP代码审计、函数特性以及一些基础Web漏洞的灵活运用。题目名字叫“不过如此”&#…

2026/8/18 8:05:43 阅读更多 →

最新新闻

Pomona:基于Agentic工作流的自动化代码质量改进系统

Pomona:基于Agentic工作流的自动化代码质量改进系统

1. 项目概述:当代码质量成为“日常习惯”在大型金融科技公司,比如彭博社(Bloomberg),代码库的规模动辄数百万行,由数千名工程师共同维护。一个普遍存在的挑战是:如何在不中断核心功能开发、不增…

2026/8/19 8:49:47 阅读更多 →
DM HUGE 表:达梦数据库中高效处理大数据的利器

DM HUGE 表:达梦数据库中高效处理大数据的利器

一、DM HUGE 表概述 1.1 DM HUGE 表的定义与特点 DM HUGE 表是达梦数据库中专门设计用于存储和管理大规模数据的一种特殊表结构。与普通表相比,DM HUGE 表在存储容量、查询性能和数据管理方面具有显著优势。主要特点包括: 支持超大规模数据存储&#xff…

2026/8/19 8:49:47 阅读更多 →
右键菜单管理:我把两屏长的菜单清到一屏,全程只用开关没碰注册表

右键菜单管理:我把两屏长的菜单清到一屏,全程只用开关没碰注册表

右键菜单管理:我把两屏长的菜单清到一屏,全程只用开关没碰注册表 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 装到第30个软件之后&…

2026/8/19 8:49:47 阅读更多 →
spring之事务底层源码解析【TL spring15】

spring之事务底层源码解析【TL spring15】

abstractPlatformTransactionManagerTransactionInterceptor强制回滚:

2026/8/19 8:49:47 阅读更多 →
学工系统专业厂家解决方案,打造高效便捷的学生工作管理平台

学工系统专业厂家解决方案,打造高效便捷的学生工作管理平台

✅作者简介:合肥自友科技 📌核心产品:智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…

2026/8/19 8:49:47 阅读更多 →
Karma上海车展战略解析:中国化与平台化双轮驱动,三款新车重塑豪华电动车市场

Karma上海车展战略解析:中国化与平台化双轮驱动,三款新车重塑豪华电动车市场

1. 从“复活”到“新生”:Karma在上海车展的战略信号 如果你关注高端电动车市场,或者对汽车行业的“复活”故事感兴趣,那么今年上海车展上Karma Automotive的动向,绝对值得你花时间琢磨。这家公司身上有太多标签:源自破…

2026/8/19 8:48:47 阅读更多 →

日新闻

【单片机课程设计/毕业设计】基于 STM32 与 WiFi 模块的室内通风智能管控系统设计 基于 STM32 的人体存在感知自适应风扇控制系统设计(018503)

【单片机课程设计/毕业设计】基于 STM32 与 WiFi 模块的室内通风智能管控系统设计 基于 STM32 的人体存在感知自适应风扇控制系统设计(018503)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/8/19 0:00:30 阅读更多 →
AI如何驱动数学猜想生成:从大语言模型到自动化数学发现

AI如何驱动数学猜想生成:从大语言模型到自动化数学发现

1. 项目概述:当AI开始“猜”数学定理 最近在AI研究圈里,一个名为“Moonshine”的项目引起了不小的讨论。这名字本身就挺有意思,直译是“月光”,但在数学史上,它特指一个神秘而美丽的联系——魔群月光猜想,连…

2026/8/19 0:00:30 阅读更多 →
WarcraftHelper 魔兽争霸3优化实战指南

WarcraftHelper 魔兽争霸3优化实战指南

WarcraftHelper 魔兽争霸3优化实战指南 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 一台刚配的新电脑,跑《魔兽争霸3》却卡成 PPT——这…

2026/8/19 0:02:31 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/18 9:15:35 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/18 9:06:28 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/18 9:04:56 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/19 5:04:55 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/19 7:42:22 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/17 18:55:55 阅读更多 →