SkyWalking Java Agent 线程池场景内存泄漏排查:Worker 线程增强与跨线程追踪修复指南
可观测性后端微服务云原生【免费下载链接】skywalkingAPM, Application Performance Monitoring System项目地址https://gitcode.com/gh_mirrors/sky/skywalking点击查看免费下载本文基于 Memory-leak-enhance-Worker-thread.md 展开结合仓库内的 Trace 数据协议与上下文传播协议文档进行源码级佐证。文章讲解在使用线程池时TraceSegment数据无法上报、内存无法回收内存泄漏的典型故障其根因是 SkyWalking Java Agent 对 Worker 线程的增强机制与跨线程追踪设计并给出「使用受支持线程调度框架」与「自定义线程池 RunnableWrapper包装任务」两种可直接落地的修复方案帮助读者在 SpringAsync、自定义ExecutorService等场景下正确完成跨线程追踪。问题现象线程池中的 TraceSegment 无法上报内存无法回收官方 FAQ 给出了这个问题的标准描述When using a thread pool,TraceSegmentdata in a thread cannot be reported and there are memory data that cannot be recycled (memory leaks).翻译过来即在使用线程池时某个线程中的TraceSegment数据无法上报且存在无法被回收的内存数据即内存泄漏。要理解这个问题首先需要明确TraceSegment在 SkyWalking 中的定位。根据 trace-data-protocol-v3.md 中的定义Segment 是 SkyWalking 中的独特概念它应当包含单个 OS 进程内一次请求的全部 Span通常对应基于语言单线程的一次执行。上报时Agent 通过SegmentObject消息包含traceId、traceSegmentId、spans、service、serviceInstance等字段将整段数据一次性发给后端。后端通过TraceSegmentReportService的 gRPC 流式接口接收这些段数据仓库中的 GRPCNoServerTest.java 就演示了TraceSegmentReportServiceGrpc建立上报通道、collect(StreamObserverSegmentObject)发送段数据的调用方式。由此可见TraceSegment是 Agent 侧一次追踪的完整数据载体它必须被完整地构建、最终上报并释放。一旦某个执行单元这里是线程池中的任务线程上的追踪上下文没有正确建立该段数据既无法形成完整链路上报给 OAP又会滞留在内存中无法被回收最终表现为数据缺失 内存泄漏的双重故障。复现示例在 ThreadFactory 中包装 Runnable 的错误姿势FAQ 给出了一个会触发该问题的典型写法使用 Spring 的ThreadPoolTaskExecutor并自定义线程工厂ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setThreadFactory(r - new Thread(RunnableWrapper.of(r)));这段代码的意图是让线程池创建的每个线程都携带追踪能力因此在ThreadFactory.newThread(Runnable r)里对传入的r套了一层RunnableWrapper.of(r)。但从结果上看它正是内存泄漏与数据无法上报的诱因。其关键问题在于ThreadFactory的newThread(Runnable r)只在创建 Worker 线程时被调用它拿到的是该线程的首任务或初始任务而不是后续每次提交进来的任务追踪上下文的捕获发生在RunnableWrapper.of(...)被调用的瞬间。在ThreadFactory中包装等于在线程创建时刻捕获上下文而真实的业务任务往往是在之后的不同线程上下文中提交的因此后续提交任务的追踪上下文无法传递到执行线程跨线程链路断裂段数据无法正确完成与上报。结论包装的位置错了。上下文必须在任务提交点捕获并传递而不是在线程创建点。根因分析跨线程追踪为什么必须增强任务线程FAQ 原文从设计层面对根因做了两点总结Worker 线程在使用线程池时会被增强Worker threads are enhanced when using the thread pool基于 SkyWalking Java Agent 的设计跨线程追踪时必须增强任务线程when tracing a cross thread, you must enhance the task thread。结合仓库协议文档可以进一步理解第二点背后的数据模型在 trace-data-protocol-v3.md 中SegmentReference消息专门用于表达两个已有 Segment 之间的关联并通过RefType区分两种引用类型RefType含义说明CrossProcess跨进程引用指向另一个 OS 进程中的父 Segment对应 RPC 场景CrossThread跨线程引用指向同一进程内、另一个线程中的父 Segment仅用于具有线程概念的语言当一次追踪从提交线程跳到线程池的执行线程时子段需要通过refs携带指向父段提交线程中的段的CrossThread引用字段说明中明确写着refType CrossThread时父段与当前段属于同一服务、同一实例。也就是说跨线程不是断链而是通过SegmentReferenceCrossThread 类型把执行线程中的新段挂到提交线程的段上形成完整链路要做到这一点执行任务的线程必须被增强——它需要能感知上下文、创建携带引用关系的新段并在任务结束后把段数据上报、释放。同样在跨进程场景Agent 通过sw8传播头见 x-process-propagation-headers-v3.md传递traceId / parentTraceSegmentId / parentSpanId等 8 个字段而跨线程场景则在进程内完成类似的信息传递。此外可选的关联上下文协议见 x-process-correlation-headers-v1.md也要求当追踪上下文跨线程、跨进程传播时关联上下文应一并传播。这些设计共同决定了任务线程必须被正确增强并携带上下文否则执行线程上产生的段缺少父子引用、无法归并到原链路数据滞留在 Agent 内存中形成泄漏。解决方案一使用受支持的线程调度框架零改造如果业务本身运行在 SkyWalking Java Agent 官方支持的线程调度框架Thread Schedule Framework之上则无需任何代码修改即可完成跨线程追踪。FAQ 给出的指引是查阅 SkyWalking Java Agent 支持的框架清单Supported-list其中典型的例子是Spring Framework 的Async——Agent 的相应插件已经处理了任务提交与执行的上下文传递开发者只需要正常使用框架能力即可。因此如果你的代码满足以下条件优先走这条路使用的是受支持的调度框架如 SpringAsync、以及清单中列出的其他线程调度组件不需要自定义线程工厂、自定义包装逻辑希望最小化侵入、避免自行包装带来的上下文处理错误。此时应移除上文中在ThreadFactory里包装RunnableWrapper的自定义逻辑恢复框架默认行为让插件负责跨线程传播。解决方案二自定义线程池场景使用 RunnableWrapper 包装提交任务如果使用的是自定义线程池Custom Thread Pool则必须手动增强任务线程。FAQ 给出的标准做法是在任务提交时用RunnableWrapper.of(task)包装任务而不是在线程工厂里包装。FAQ 原文示例Executors.newFixedThreadPool场景ExecutorService executorService Executors.newFixedThreadPool(1); executorService.execute(RunnableWrapper.of(new Runnable() { Override public void run() { //your code } }));为了让该示例真正可运行、可维护下面补充为完整形态含导入、异常处理与优雅关闭import org.apache.skywalking.apm.toolkit.trace.RunnableWrapper; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class CrossThreadTraceDemo { public static void main(String[] args) throws InterruptedException { ExecutorService executorService Executors.newFixedThreadPool(1); // 在任务提交点包装 Runnable // RunnableWrapper.of() 会捕获提交线程当前正在追踪的上下文 // 并在执行线程运行 run() 前将其恢复从而实现跨线程上下文传递。 executorService.execute(RunnableWrapper.of(new Runnable() { Override public void run() { // 你的业务逻辑此处运行在线程池的 Worker 线程上 // 但由于任务已被增强wrapped该线程产生的 Span 会 // 通过 CrossThread 引用关联到提交线程的 Segment 上。 } })); executorService.shutdown(); executorService.awaitTermination(10, TimeUnit.SECONDS); } }要点解读包装时机 提交时机RunnableWrapper.of()应出现在execute()/submit()调用的参数位置即任务进入队列的那一刻此时提交线程的追踪上下文处于活状态可以被捕获不要在线程工厂中包装如本文复现示例所述ThreadFactory中的包装捕获的是线程创建时刻的上下文无法覆盖后续每个任务的真实上下文更多用例FAQ 明确指向跨线程解决方案 API文档across thread solution APIs位于 apache/skywalking-java 仓库的Application-toolkit-trace-cross-thread.md其中包含Runnable、Callable等多形态任务的包装用法。注意该 Toolkit 位于 Java Agent 仓库skywalking-java与当前 OAP 后端仓库skywalking属于同一生态的不同组件集成时需确保 Agent 与 Toolkit 版本配套。两种方案对比与选型建议维度线程调度框架如 Spring Async自定义线程池 RunnableWrapper代码改造量零改造需在提交点包装任务适用场景框架能力覆盖且受 Agent 支持清单认可自有线程池、框架插件未覆盖的场景上下文传递由 Agent 插件自动完成由RunnableWrapper.of()在提交点捕获、执行点恢复出错风险低中需避免在 ThreadFactory 等错误位置包装验证修复效果完成修复后建议从两个维度验证链路完整性在 UI 上查看该线程池任务对应的 Trace确认执行线程产生的 Span 已通过 CrossThread 引用挂接到提交线程的 Segment 上形成完整链路可结合 trace-data-protocol-v3.md 中SegmentReference/RefType的语义理解 UI 上的连线关系内存回收对应用做持续压力运行并观察堆内存曲线确认不再出现随时间线性增长的滞留数据同时确认后端 OAP 能持续收到该服务上报的 Segment后端上报入口参见 TraceSegmentReportServiceHandler.java。关联资料本文档Memory-leak-enhance-Worker-thread.mdFAQ 索引docs/en/FAQ/README.mdRuntime 分类下列出了本问题Trace 数据协议Segment / SegmentReference / RefType 定义trace-data-protocol-v3.md跨进程传播头协议 sw8x-process-propagation-headers-v3.md关联上下文传播协议 sw8-correlationx-process-correlation-headers-v1.md小结线程池场景下的TraceSegment 无法上报 内存泄漏本质是跨线程追踪上下文没有在正确的时机被增强与传递。牢记 SkyWalking Java Agent 的设计约束——跨线程必须增强任务线程优先选择 Agent 官方支持的线程调度框架如 SpringAsync零改造接入自定义线程池则务必在任务提交点使用RunnableWrapper.of(task)包装杜绝在ThreadFactory中包装的错误姿势。这样既能保证跨线程链路的完整性也能让段数据正常上报、及时回收从根本上消除内存泄漏。赞分享可观测性后端微服务云原生【免费下载链接】skywalkingAPM, Application Performance Monitoring System项目地址https://gitcode.com/gh_mirrors/sky/skywalking点击查看免费下载相关推荐SkyWalking Java Agent 线程池场景内存泄漏排查Worker 线程增强与跨线程 TraceSegment 上报SkyWalking Java Agent 线程池场景内存泄漏排查Worker 线程增强与跨线程 TraceSegment 上报 导读 本文围绕 SkyWal可观测性APM链路追踪指标监控日志分析微服务线程级内存追踪mimalloc如何让内存泄漏排查效率提升10倍线程级内存追踪mimalloc如何让内存泄漏排查效率提升10倍 你是否曾为多线程程序的内存泄漏问题头疼明明总内存占用异常增长却找不到具体是哪个线程在偷偷内存管理系统编程艾尔登法环存档编辑器3步解锁游戏无限可能告别重复刷图的烦恼艾尔登法环存档编辑器3步解锁游戏无限可能告别重复刷图的烦恼 还在为艾尔登法环中重复刷装备而烦恼吗想要快速体验不同build却不想从头开始ER Save桌面应用游戏开发上一篇偏微分方程可视化终极指南GitHub项目中的热传导方程三维动画模拟下一篇ntlm_theft vs 传统钓鱼为什么这款开源工具能绕过Windows Defender检测创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

投稿前如何用审稿人视角自审论文:一套可操作的审稿Skill集合

投稿前如何用审稿人视角自审论文:一套可操作的审稿Skill集合

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

2026/9/20 19:11:12 阅读更多 →
Linux驱动自动加载机制:从模块匹配到设备节点生成

Linux驱动自动加载机制:从模块匹配到设备节点生成

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

2026/9/20 19:11:12 阅读更多 →
XiaoMusic:小爱音箱免费听全网音乐的方法

XiaoMusic:小爱音箱免费听全网音乐的方法

XiaoMusic:小爱音箱免费听全网音乐的方法 【免费下载链接】xiaomusic 使用小爱音箱播放音乐,音乐使用 yt-dlp 下载。 项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic 对音箱说"播放歌曲七里香",却收到一句&q…

2026/9/20 19:11:12 阅读更多 →

最新新闻

GD32H759工控实战:RT-Thread下ADC/DAC驱动与硬件过采样调优

GD32H759工控实战:RT-Thread下ADC/DAC驱动与硬件过采样调优

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

2026/9/20 20:24:56 阅读更多 →
自托管项目管理平台迁移实践:TomiHub部署与AI Brain接入全记录

自托管项目管理平台迁移实践:TomiHub部署与AI Brain接入全记录

上个月我把团队的项目管理数据从一家商业看板工具里导了出来,导出的 CSV 压完还有 80 多 MB。真正让我下决心的不是导出麻烦,而是那家工具突然改了定价策略,免费版几乎砍掉了全部看板功能,团队 12 个人,一个月光协作席…

2026/9/20 20:24:56 阅读更多 →
Docker 部署 n8n 本地化指南:从环境搭建到运维备份

Docker 部署 n8n 本地化指南:从环境搭建到运维备份

写这篇文章的时候,我一直在回想自己当初第一次把 n8n 跑起来的样子。当时最大的问题不是 n8n 本身,而是 Docker 环境怎么都装不好,卡在虚拟化检测那一关整整一下午。所以这次我把整条部署路径拆开揉碎,从为什么选 Docker、环境怎么…

2026/9/20 20:24:56 阅读更多 →
Flink Plugins 插件机制详解:文件系统与 Metric Reporter 的隔离加载与实战部署

Flink Plugins 插件机制详解:文件系统与 Metric Reporter 的隔离加载与实战部署

Flink Plugins 插件机制详解:文件系统与 Metric Reporter 的隔离加载与实战部署 【免费下载链接】flink 项目地址: https://gitcode.com/gh_mirrors/fli/flink Apache Flink 从 1.9 版本引入 Plugins(插件)机制,通过受限的…

2026/9/20 20:24:56 阅读更多 →
Isaac Lab仿真录制与回放实战:从一条演示到可分享视频的完整流程

Isaac Lab仿真录制与回放实战:从一条演示到可分享视频的完整流程

Isaac Lab仿真录制与回放实战:从一条演示到可分享视频的完整流程 【免费下载链接】IsaacLab Unified framework for robot learning with multi-physics/renderer support 项目地址: https://gitcode.com/GitHub_Trending/is/IsaacLab 一条演示数据在 Isaac …

2026/9/20 20:24:56 阅读更多 →
浪潮服务器ESXi 6.7 RAID驱动集成实战:ESXi-Customizer-PS打包与避坑指南

浪潮服务器ESXi 6.7 RAID驱动集成实战:ESXi-Customizer-PS打包与避坑指南

1. 为什么浪潮服务器装ESXi 6.7总在RAID卡上翻车浪潮的服务器在政企、金融、教育行业里保有量极大,NF5280M5、NF5180M5、SA5212M5这些型号几乎是机房里的常客。但凡是自己动手给这些机器装过VMware ESXi 6.7的人,大概率都经历过同一个场景:U盘…

2026/9/20 20:23:56 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →