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/10/19 3:18:13 阅读更多 →
西门子S7-1200 PLC定时器深度解析:从核心原理到实战应用

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

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

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

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

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

2026/10/18 22:58:21 阅读更多 →

最新新闻

Sunshine 虚拟手柄配置指南:3 项检查加 1 份最小配置,串流 PC 游戏

Sunshine 虚拟手柄配置指南:3 项检查加 1 份最小配置,串流 PC 游戏

Sunshine 虚拟手柄配置指南:3 项检查加 1 份最小配置,串流 PC 游戏 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine Sunshine 是自托管游戏串流服务器&#…

2026/10/19 3:18:06 阅读更多 →
激活函数深度解析:从ReLU到自定义设计与工程落地

激活函数深度解析:从ReLU到自定义设计与工程落地

1. 激活函数的角色认知:它远不止"加个非线性"那么简单我在项目里见得太多了——很多人调模型效果不好,第一个怀疑网络结构,第二个怀疑学习率,第三个怀疑数据增强,查了一圈最后才发现,问题出在一个…

2026/10/19 3:18:06 阅读更多 →
Qt Creator快捷键实战:C++与QML开发流效率加速指南

Qt Creator快捷键实战:C++与QML开发流效率加速指南

1. 这不是键盘说明书,而是Qt开发者每天都在用的“肌肉记忆加速器”你有没有过这样的经历:刚写完一行代码,想快速跳到函数定义处,却下意识按了CtrlClick——结果光标纹丝不动;或者在调试时想打断点,手已经伸…

2026/10/19 3:18:06 阅读更多 →
从零构建最小可用AI Agent:感知-思考-行动闭环与工具调用实现

从零构建最小可用AI Agent:感知-思考-行动闭环与工具调用实现

这两年大模型应用层最热的话题,一个是RAG,另一个就是智能Agent。我身边的开发者几乎人手一个"Agent"项目——但真正做下去才发现,把大模型接进聊天框只能叫Demo,让它自己选工具、定步骤、执行完再看结果决定下一步&…

2026/10/19 3:18:06 阅读更多 →
Django admin 导出 CSV 完整指南:从编码到权限、性能优化

Django admin 导出 CSV 完整指南:从编码到权限、性能优化

前阵子帮一个内部运营后台加“Django admin 后台数据导出 csv”功能,刚开始以为就是用csv模块写个 HttpResponse 的事,真做起来才发现里面藏着不少坑:Excel 打开中文乱码、文件名变成一堆百分号、导出来的时间格式没法直接看、外键全是 id、想…

2026/10/19 3:18:06 阅读更多 →
Flutter工程规范实战:用Claude Code和Codex约束AI写代码

Flutter工程规范实战:用Claude Code和Codex约束AI写代码

最近我在几个 Flutter 项目里试了用 Claude Code 和 Codex 来写代码,效果确实惊艳,但翻车概率也一点都不低。最典型的情况是:AI 能独立完成一个小功能,却会在你根本没注意到的地方破坏既有约定——混用状态管理方案、跳过异常处理…

2026/10/19 3:17:05 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →