jvisualvm.exe实战:从堆dump到线程堵塞的JVM问题排查指南

1. 别急着上重量级工具:jvisualvm.exe为什么是排查JVM问题的第一站

先说个我自己的真实经历。去年某天下午,线上一个订单服务突然开始频繁告警,接口平均耗时从50ms直接飙到3秒多,CPU占用率稳定在95%以上。当时组里几个同事的第一反应是上各种专业APM平台,又是拉监控大盘又是翻调用链,折腾了半个多小时还是一头雾水。最后我让他们把服务所在机器的JDK目录翻开,找到bin/jvisualvm.exe双击打开,连接上目标进程,两分钟就锁定了问题——一个线程池里的任务在等一把永远等不到的锁,背后是一个数据库连接池被打满的连锁反应。

这个场景我想很多做Java开发的朋友都不陌生。一提到JVM调优、性能排查,网上教程张口就是Arthas、MAT、JFR,好像不上一堆高大上的工具就不好意思说自己会排查。但实际工作里,jvisualvm.exe这个JDK自带的工具才是性价比最高的起点。它不需要额外安装、不需要目标服务引入任何agent、不修改业务代码,打开即用,而且覆盖了堆栈内存查看、线程堵塞分析、堆dump生成这三块最核心的排查能力。

这篇文章我就围绕jvisualvm.exe来写,重点讲三件事:怎么看堆栈内存、怎么定位线程堵塞、以及实战中怎么把这两个信息结合起来快速锁定线上问题。适合刚接触JVM排查的初级开发,也适合那些平时只用jstack和jmap、但想找个更直观图形化工具的工程师。顺便说一句,这篇文章里所有的排查思路,都是我真实在项目里用过的,不是那种配好环境截几张图就完事的demo教程。

1.1 jvisualvm.exe和VisualVM的关系,以及你的JDK里到底有没有它

先澄清一个常见的认知混淆。很多人以为jvisualvm是一个独立下载的工具,其实它从JDK 6 Update 7开始就被打包进JDK里了,Windows环境下位于%JAVA_HOME%\bin\jvisualvm.exe。从JDK 9开始Oracle在发行版里把VisualVM单独拆出去了,所以在最新的JDK 11、17的bin目录下你可能找不到它,需要去VisualVM官网下载独立版本。但大多数公司生产环境还在用JDK 8,jvisualvm.exe就在那里躺着,只是很多人从来没双击过它。

另外要注意,VisualVM的核心功能是基于Java Management Extensions(JMX)技术实现的。也就是说,jvisualvm能看到的内存、线程、类加载信息,本质上都是通过JMX端口从目标JVM里拉取的数据。这也是为什么远程连接时需要额外配置JMX参数,本地连接则直接使用attach机制、不需要任何配置。搞清楚这一层原理,后面配置远程连接时就不会一头雾水。

1.2 连接本地进程和远程JVM:从双击到看见界面的完整步骤

本地连接没什么好说的——启动jvisualvm.exe,左侧会自动列出本机所有正在运行的JVM进程,双击进程名就能看到Overview、Monitor、Threads、Sampler、Profiler这几个Tab。但如果你的服务跑在远程服务器上或者Docker容器里,就需要走JMX远程连接了。这里给出我常用的启动参数模板,可以直接抄:

java -Dcom.sun.management.jmxremote \ -Dcom.sun.management.jmxremote.port=9099 \ -Dcom.sun.management.jmxremote.authenticate=false \ -Dcom.sun.management.jmxremote.ssl=false \ -Djava.rmi.server.hostname=192.168.1.100 \ -jar your-service.jar

这几个参数一个个说。jmxremote.port=9099是暴露JMX服务的端口,authenticate=false和ssl=false是为了内网调试方便,生产环境建议至少开SSL。最关键的是java.rmi.server.hostname,很多人在这一步踩坑——JMX除了监听你指定的9099端口外,还会动态开一个随机端口用于RMI通信,如果你不指定hostname,服务器上报给客户端的地址可能是内网IP或者127.0.0.1,导致客户端能连9099却连不上随机端口,表现就是右下角转圈半天然后报连接失败。

连接成功后,左侧会出现刚才填写的host:port节点,双击进去就能看到实时的堆内存折线图、CPU使用率、线程数和类加载数。这里有个技巧:右侧Monitor Tab的右上角有一个“Heap Dump”按钮和“Thread Dump”按钮,生产环境执行前务必确认对业务的影响,堆dump会触发Full GC,线程dump则几乎无感知。我先提一句,后面的章节还会专门展开。

2. 堆栈内存分析实操:从堆dump到定位内存压力点的完整动作

jvisualvm的Monitor Tab里那个堆内存折线图非常直观,刚打开就能看到Eden区、Survivor区、Old区的占用曲线。但很多人就停在这一步——看到曲线涨了又跌、跌了又涨,觉得挺好看,却不知道接下来该干什么。实际上,折线图只是告诉你"有没有问题",真正要回答"问题出在哪",必须靠堆dump。

2.1 生成堆dump的三种方式:GUI按钮、jmap命令、以及OOM自动导出

我平时最常用的生成堆dump的方式其实不是点jvisualvm界面里的按钮,而是用jmap,原因后面说。先列一下三种方式的适用场景:

方式命令/操作适用场景副作用
jvisualvm界面按钮在Monitor Tab点“Heap Dump”单机调试、流量低谷期触发Full GC,应用可能会短暂停顿
jmap命令jmap -dump:live,format=b,file=/path/heap.hprof <pid>远程SSH登录服务器操作live参数会触发Full GC
OOM自动导出JVM参数加-XX:+HeapDumpOnOutOfMemoryError预防性兜底,应对突然OOM仅OOM时触发,不影响平时运行

如果你能SSH到服务器,我建议用jmap而不是依赖jvisualvm连接远程再点按钮——毕竟生产环境能少一步网络交互就少一分风险。命令写法:

# 先找到进程PID jps -l # 导出堆dump,live表示只保留可达对象 jmap -dump:live,format=b,file=/tmp/heap_20240117.hprof 12345

live这个参数值得单独解释一下。加上它,JVM会先做一次Full GC,然后只dump存活对象,好处是dump文件体积小、分析时干扰项少,坏处是会触发一次全停顿。如果服务对延迟极其敏感,宁可不要这个参数,直接dump整个堆,文件大一些但不会触发GC。我个人的习惯是白天高峰期用不带live的,凌晨低峰期用带live的,两头兼顾。

2.2 打开堆dump之后:Classes、Instances、Retained Size到底看哪些列

得到hprof文件后,回到jvisualvm,在左侧进程节点上右键选“Heap Dump”或者把jvisualvm的堆dump文件拖进窗口,它会打开一个独立的堆dump视图。这个视图最有价值的是“Classes”页签,里面按类列出了当前堆里的所有对象。

我第一次打开这个页签时完全不知道看什么,直到有经验的同事指点了一句话:先按“Instances”列降序排列,看哪个类的对象数量多到不正常;再按“Retained Size”列降序排列,看哪个类真正占用了大块内存。这两个指标要配合着看,因为光对象多不一定占内存多,比如Integer这种一个对象才16字节;光内存占得多也不一定对象多,比如byte[]可能就那么几个けど几个GB。

我拿一个实际遇到过的案例来说。某同步服务每次请求都会new一个“请求上下文”对象,正常情况这个对象在请求结束后就变成垃圾了。但压测时发现Retained Size里这个对象占到了堆的40%,Instances数量持续上涨不下降。进一步点开这个类,在“Instances”页签里能看到所有存活对象的列表,我挑了几个对象的引用路径一查,发现它们被挂在了一个静态ThreadLocal变量上。一看代码,业务线程在finally块里忘了调用remove(),线程池里的线程复用后ThreadLocal里的旧对象永远释放不掉。

这就是为什么我强调要看生成堆dump时处于什么运行阶段。如果是压测中的dump,你能抓到业务代码的内存泄漏;如果是压力释放后稳定阶段的dump,你看到的可能是真正的驻留内存,两者代表的问题完全不同。

2.3 OQL查询:当类名和数量对不上号时的下一步操作

有些场景光靠排序看不出来问题。比如某个服务内存稳步上升,但Class页签里所有类的Instances数量看起来都在正常范围,没有任何一个类突出。这时候就该用OQL了,jvisualvm的堆dump视图有OQL控制台入口,用类似SQL的语法就能查条件对象。

我最常用的几条OQL示例:

-- 查询所有长度超过1KB的字符串,定位大字符串缓存 SELECT s FROM java.lang.String s WHERE s.value.length > 1024 -- 查询所有数组长度超过1000的char数组 SELECT c FROM char[] c WHERE c.length > 1000 -- 按类统计实例数和占用空间 SELECT clazz, count(*) AS cnt, sum(heapbytes) AS total FROM OBJECTS GROUP BY clazz ORDER BY total DESC

OQL的语法需要一点时间适应,但它的威力在于能按条件筛选,而不是面对几万个类一个个肉眼看。比如我遇到过内存飙升但Class页签看起来正常的场景,用OQL查了一下超过1MB的byte[],很快就定位到一个缓存组件里存了全量商品信息的大JSON,容量评估失误导致占用内存远超预期。

这里需要说清楚一个边界:jvisualvm的堆dump能帮你看到对象分布,但真要分析引用链、算GC Roots路径,它不如MAT(Memory Analyzer Tool)专业。我的习惯是jvisualvm负责快速出结论、给方向,如果遇到引用关系复杂的问题,就把hprof文件导出再用MAT打开做深度分析。工具的边界要清楚,别硬拿一把锤子把所有问题都当钉子。

3. 线程堵塞排查:线程dump、锁等待、死锁检测的完整打法

线程问题比内存问题更隐蔽,因为很多线程堵塞在没有dump的瞬间是看不见的。但恰恰是jvisualvm的Threads Tab,能把线程状态实时显示成一条彩色时间线,一眼就能看出哪些线程长期处于Blocked或者Waiting状态。

3.1 Threads Tab的三种核心状态:Running、Blocked、Waiting分别意味着什么

打开Threads页签,你会看到类似泳道图的展示:每条横线代表一个线程,颜色代表当前状态。绿色Running、红色Blocked、黄色Waiting。当整个图里大部分线程都变成红色和黄色,而绿色寥寥无几时,基本可以断定系统遇到了线程堵塞。

这里必须区分两个容易混淆的状态:

  • Blocked(红色):表示线程尝试进入synchronized代码块或方法时,锁被其他线程持有,进入了锁等待队列。这种状态往往是锁竞争导致的。
  • Waiting(黄色):表示线程执行了wait()、join()、park()等方法,主动进入等待状态。这种不一定是坏事,比如线程池空闲线程就处于Waiting。

极端情况下,你看到的是几乎全屏红色或者全屏黄色+绿色穿插。全屏红色的场景往往是某个持锁线程卡在IO操作上不释放锁,其他线程全部Blocked等它。全屏黄色可能是指定线程都在等待某个永远等不到的通知。这两种情况的排查方向完全不同,前者查持锁线程在等什么IO,后者查等待队列是否有人负责唤醒。

3.2 线程dump按钮和jstack命令:哪个快、哪个全

说到线程堵塞排查,很多人第一反应是jstack <pid>。jstack的输出是全文本的,会列出每个线程的栈、线程状态、锁信息,非常详细。但jstack的输出可读性不高,信息太多之后反而不知道从哪看起。jvisualvm的Thread Dump视图其实是把同样的数据做了可视化处理。

实际操作路径:在Threads页签上方点“Thread Dump”按钮,jvisualvm会生成一份快照,把每个线程的栈信息、持有的锁、等待的锁全部列出来。和jstack不同的是,它的展示带颜色高亮,能帮你快速找到显示为红色Blocked状态的线程。点击某个线程还能展开调用栈,看到它阻塞在哪一行代码。

我在实战里的顺序通常是这样的:先看Threads时间线确认大方向(是全红还是全黄还是正常),再点Thread Dump拿一份快照,先看红色Blocked的线程有哪些、它们在等哪把锁,然后往持有那把锁的线程上追,看持锁线程的栈停在哪。用jstack也可以完成同样的分析,但可视化状态下我大概能节省一半的阅读时间。

3.3 死锁检测:不是只有DDL和SQL才会死锁,Java代码一样会

jvisualvm还内置了一个很实用的功能:死锁检测。当你打开一个线程dump后,在dump视图里能看到“检测死锁”的按钮(不同版本位置不同,一般在工具栏或者线程标签页里)。点击后jvisualvm会自动分析锁等待关系,如果检测到循环等待,会直接显示死锁涉及的线程和锁的持有等待链路。

这个功能帮我在模拟场景下快速复现过一次教科书式死锁。两个线程各自持有一把锁,然后互相去申请对方的锁,形成A等B、B等A的环。检测结果直接把两个线程和对应的锁对象列出来,连代码行都标好了。说实话,以前用jstack排查死锁时,要在几百行输出里去人工比对哪个线程持有哪把锁、又在等哪把锁,眼睛都要看花了。jvisualvm这个一键检测算是解放了劳动力。

但死锁只是线程堵塞的一种极端形式,实际生产里更多的线程堵塞其实没有形成死锁环,而是部分线程被异常拖住、长时间不释放锁,导致大量其他线程Blocked。这种情况jvisualvm同样能分析,只是需要你按锁的持有链路去追——先找持锁线程的栈,再看它停在哪一步,是哪次IO或者网络请求迟迟没有返回。

4. 一次模拟线上事故的综合排查案例:从客户反馈到定位根因的全过程

前面把堆栈内存和线程堵塞的单独操作都讲了一遍,但这还不够。真正线上排查时,内存和线程往往是纠缠在一起的——内存泄漏导致GC频繁,GC频繁导致STW停顿,STW停顿导致线程堆积,线程堆积又反过来加剧内存压力。所以这一节我完整复盘一次我在模拟环境里复现的“综合事故”,尽量还原真实排查的每一步决策。

4.1 场景设定:接口变慢、CPU不高、内存曲线却稳定爬升

模拟环境里我部署了一个简单的订单查询服务,对外暴露HTTP接口。初始状态一切正常,但压测跑到第20分钟时,接口响应时间从80ms涨到4秒,但CPU利用率只有30%——这个数据组合很关键,CPU不高说明不是计算密集问题,更可能是线程在等待某种资源。

我的第一步是打开jvisualvm.exe连接进程,先看Monitor Tab的内存曲线:堆内存占用像楼梯一样逐级上升,每次GC后降一点,但降不到初始水平,整体趋势往上走。这是典型的内存泄漏信号。同时看Threads Tab,发现大量线程处于Blocked状态,blocked线程又集中在两个线程池里。

这种组合让我立刻形成两个假设:第一,存在内存泄漏,导致GC频繁;第二,某些线程持有锁不放,导致业务线程大面积Blocked。但哪个是因哪个是果,还需要进一步求证。

4.2 第一步取证:先捞线程dump,确认堵塞是否由锁竞争引起

我选择先做线程dump而不是先做堆dump,原因很简单:线程dump几乎没有副作用,而堆dump会触发Full GC,最好放到后面做。在jvisualvm的Threads Tab点下“Thread Dump”按钮,我快速扫了一遍Blocked状态的线程,发现它们都卡在一个HTTP客户端连接池的获取连接方法上,等的是同一个连接池内部的锁。

这个信息很有价值。线程卡在获取连接上,通常意味着连接池空了,所有连接都被借出且没有归还。那问题就转移到“连接为什么没归还”上了。顺着Blocked线程的栈往下追,发现它们的上游业务线程也有很多处于Waiting状态,等的是一个Redis连接池的信号量。

到这里,我基本能拼出半幅图:Redis连接池满 → 业务线程等待 → HTTP调用链上的连接持有不放 → HTTP连接池也满 → 大量线程Blocked。但还有一个关键问题没解开:Redis连接池为什么满了?连接为什么归还不了?这个问题靠线程dump已经不太够,得看内存。

4.3 第二步取证:堆dump定位异常对象,锁比赛点找到Root Cause

在低峰期我点了“Heap Dump”按钮,jvisualvm里打开hprof文件后直接按Retained Size排序。排在最前面的类让我有点意外:一个名字类似“RedisCommand”的缓存对象占了将近30%的堆空间。点进去看实例列表,发现了成百上千个指向同一个Redis命令的缓存对象,而这些对象被一个静态Map持有,Map里的key是某个请求ID的MD5,value是一个带有大量元数据的命令包装对象。

看到这里整条链路就通了:业务代码在每次请求时把Redis命令包装对象放进了静态缓存Map,正常情况下请求结束后应该移除,但代码只在某条异常分支里写了删除操作,正常路径漏掉了remove。于是请求量一大,Map无限增长,Redis连接池里的命令对象越来越大、响应越来越慢,连接持有时间越来越长,最终连接池耗尽,线程大面积Blocked,接口全面变慢。

这个案例想说明的其实不是代码bug本身,而是排查思路的优先级:先用线程dump排除锁竞争带来的即时故障,再用堆dump定位让故障持续的根本原因。两层信息缺一不可——只看线程dump,你会以为是Redis配置问题,重启连接池治标不治本;只看堆dump,你会盯着内存泄漏修代码,却不知道为什么接口现在卡成这个鬼样子。

4.4 修复与验证:改掉缓存Map的remove逻辑,内存曲线回归平缓

修复方案很简单:在业务代码的finally块里补充remove操作,确保每个请求结束后清掉静态缓存Map里的entry。改完之后重启服务,重新压测,观察三个指标:内存曲线从“楼梯上升”变成“锯齿波动”,Threads Tab里Blocked线程数量降为0,接口响应时间回到80ms。

这里我想强调一下验证阶段的注意事项:重启后只看内存平稳还不够,建议再用jstack手动抓一次线程快照,确认没有线程堆积;同时配合jstat -gcutil <pid> 1000观察GC频率,如果Young GC和Full GC间隔都回归正常,说明整个链路都健康了。内存、线程、GC三者的数据要对照着看,才能确认问题真的被根除,而不是被重启掩盖。

5. jvisualvm的边界和延伸:什么时候必须换工具,以及工具选型的心法

虽然我大力推荐jvisualvm作为排查第一站,但它确实不是万能的。有一类场景明显超出它的能力范围——深度堆分析。比如你需要精确计算某个对象到GC Roots之间有多少条引用路径、哪条路径是强引用哪条是弱引用,jvisualvm的堆dump视图做不到。这种活我都是把同一份hprof文件扔给MAT去处理的。

5.1 常用排查工具对比表:jvisualvm、jstack、jmap、MAT、Arthas各自擅长什么

我整理了一张表,把常用的几样工具按使用场景做了对比,方便你在面对不同问题时快速选型:

工具核心能力上手成本适用场景
jvisualvm图形化查看内存曲线、线程时间线、堆dump低,GUI操作日常巡检、快速定位方向
jstack纯text线程dump中,需要读输出脚本化采集线程快照
jmap生成堆dump低服务端快速导出hprof
MAT堆dump深度分析,对象引用链、GC Roots路径高,需要熟悉概念内存泄漏归因、复杂引用分析
Arthas在线反编译、watch方法调用、动态修改日志级别高,命令行交互无法重启服务的线上热诊断

这里多说一句Arthas。它其实和jvisualvm有部分功能重叠,比如都能看线程状态。Arthas的独特优势在于它能在线执行watch、trace这类字节码增强操作,直接看某个方法的入参和返回值,这在定位业务逻辑问题时比jvisualvm强大得多。但Arthas需要额外引入工具包,而jvisualvm是JDK自带的,从“零成本启动排查”的角度看,jvisualvm永远是第一选择。

5.2 远程连接性能开销和安全性:连接生产环境前必须知道的三件事

用jvisualvm远程连接生产环境不是没有代价的。JMX本身会占用一定的网络带宽和内存,尤其当你打开Profiler做CPU采样时,目标JVM的开销会明显上升。我给自己定了一条规矩:生产环境只做短时连接,做完一个明确的排查动作就断开,绝不挂在那边长时间观察。

安全性方面也有讲究。不带SSL不带认证的JMX端口等于裸奔,如果你在一个可被外部访问的机器上开了-Dcom.sun.management.jmxremote.authenticate=false,理论上别人扫到端口就能连进来读取你的JVM内部信息。所以生产环境至少要做到两点:一是JMX端口只在防火墙内部开放,或者干脆绑定本地回环地址后用SSH隧道转发;二是必须开启SSL和密码认证。下面是带认证的配置模板:

-Dcom.sun.management.jmxremote.port=9099 \ -Dcom.sun.management.jmxremote.authenticate=true \ -Dcom.sun.management.jmxremote.ssl=true \ -Dcom.sun.management.jmxremote.password.file=/path/jmxremote.password \ -Dcom.sun.management.jmxremote.access.file=/path/jmxremote.access

这里有个官方文档几乎不会明说的坑:jmxremote.password文件的权限必须是当前用户可读写,否则JVM会拒绝加载并报错。jmxremote.access文件则用来控制每个用户是只读权限还是读写权限。我把管理账号配置成readwrite,把监控账号配置成readonly,平时巡检用只读账号就够了。

6. 一些长期被低估的日常用法:把jvisualvm从排障工具变成性能维护工具

很多人只有在线上出事故时才想起jvisualvm,平时从来不碰。这其实浪费了它很大的价值。我这几年的习惯是,每次上线新服务或者大版本发布后,都主动打开jvisualvm连接一次,把内存曲线、线程数、类加载数的基线数据记录下来。有了基线,下次出问题一眼就能看出偏离了多少,排查效率翻倍。

6.1 CPU Sampler和Profiler:除了看内存线程,jvisualvm还能做热点方法分析

jvisualvm的Sampler Tab提供了CPU和内存两类采样。CPU采样就是每隔一段时间抓一次所有线程的调用栈,统计每个方法被采样到的次数,从而近似得出热点方法排名。这个功能对定位CPU飙高的场景特别有用——不用加任何agent,点个按钮跑一两分钟就能看到排名靠前的方法。

我记忆比较深的一个案例:某服务的CPU占用率总是间歇性冲到80%以上,但持续时间很短,jstack抓到过几次都没看出端倪。后来用Sampler跑了5分钟,方法排行里一个加密工具类的generateKey方法赫然排在第一位。顺着业务代码一查,原来每次HTTP请求都要重新生成一次RSA密钥对,而生成密钥对是出了名的吃CPU。优化成启动时生成一次、后续复用后,CPU曲线立刻平了。

Profiler比Sampler更进一步,它做的是精确注入式的调用计数,结果更准但性能开销更大。我的建议是:生产环境尽量只用Sampler,Profiler留给压测环境跑全量数据。

6.2 插件体系:离线安装VisualVM插件解决高级功能的最后一块拼图

jvisualvm(以及独立版VisualVM)是支持插件机制的,默认安装在用户目录下。通过菜单Tools → Plugins可以打开插件中心,里面有不少第三方的扩展插件,比较常用的有BTrace工作台、GC日志查看器等。

有朋友遇到过一个很尴尬的情况:公司内网环境完全和外网隔离,插件中心根本打不开。解决方案是下载对应版本的nbm插件文件后,在插件中心界面点“Downloaded”按钮手动加载本地文件。需要注意插件版本必须和你安装的VisualVM版本严格匹配,否则装上去大概率报版本不兼容。我踩过一次坑,装了一个适配旧版本的插件,搞的界面都打不开了,最后把.visualvm这个用户配置目录删掉才恢复。

6.3 最后的兜底建议:把定时dump写成脚本,给未来的自己留一个救命数据

我再分享一个个人特别受益的习惯。在容易出问题的核心服务上,我会写一个简单的定时脚本,每两个小时用jmap导出一份堆dump,保留最近7天的文件。平时这些文件不占多少磁盘,但哪天服务突然OOM或者内存异常飙升,你能直接翻开事故发生前最近的dump文件看现场,而不是等事故暴露后再去复现。

脚本用cron或者Windows的任务计划程序都能实现,核心逻辑就一行:

jmap -dump:format=b,file=/data/dump/heap_$(date +%Y%m%d_%H%M%S).hprof <pid>

有人可能会问,这不就是在用jmap吗,和jvisualvm有什么关系?我的理解是,jvisualvm的价值在于解读dump,而脚本的价值在于生产dump,两者是吃和做饭的关系。定时生成的dump文件配合jvisualvm的分析能力,才是一套完整的排查闭环。学再多的工具,不如先把数据攒出来。真的到了线上事故那一刻,你会感谢当初多写了这一行脚本的自己。

相关新闻

Spring AI 初体验:ChatClient 四步链式调用快速接入大模型

Spring AI 初体验:ChatClient 四步链式调用快速接入大模型

第一次用 Spring AI 给我留下最深印象的一件事&#xff0c;不是模型本身有多智能&#xff0c;而是整个接入过程短到让我怀疑是不是漏了步骤&#xff1a;加依赖、配一段 yml、注入一个 ChatClient&#xff0c;四步链式调用就能把大模型接进 Spring Boot 项目。整个过程不需要手写…

2026/10/21 8:01:13 阅读更多 →
中文自然语言处理入门:从分词到深度学习的核心概念与实践

中文自然语言处理入门:从分词到深度学习的核心概念与实践

简介&#xff1a;这是一份面向Python中文自然语言处理初学者与进阶开发者的实战型学习资料&#xff0c;围绕分词、词性标注、命名实体识别、情感分析、主题建模及深度学习模型等核心主题展开&#xff0c;帮助读者从环境搭建一路走到聊天机器人、垃圾邮件检测、自动摘要等真实项…

2026/10/22 11:02:03 阅读更多 →
GEO源码平台部署全攻略:从环境配置到报错排查实战

GEO源码平台部署全攻略:从环境配置到报错排查实战

最近一两年&#xff0c;GEO&#xff08;Generative Engine Optimization&#xff0c;生成引擎优化&#xff09;已经从概念炒作变成了实打实的业务刚需。看着搜索结果里那些AI概览、大模型直接引用品牌信息&#xff0c;不少团队都想搭建一套自己的GEO分析平台&#xff0c;用来监…

2026/10/21 8:00:12 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年&#xff0c;我大部分时间都在跟浏览器标签页打交道&#xff0c;直到第一次把桌面应用跑起来&#xff0c;才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词&#xff0c;最开始是在某段时间频繁出现在同事的讨论里&#xff0c;一个用HTML…

2026/10/22 10:18:38 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介&#xff1a;亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档&#xff0c;主要面向智能锁安装人员、终端用户及售后维护者&#xff0c;帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件&#xff0c;大小4.37MB&#xff0c;内容结构清晰&#xff…

2026/10/22 11:01:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统&#xff0c;整车要求空载跑到8m/s&#xff0c;电机转速已经拉到额定点&#xff0c;驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令&#xff0c;转速纹丝不动&#xff0c;三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/22 9:44:47 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年&#xff0c;用它写过嵌入式驱动、做过游戏服务端&#xff0c;也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词&#xff0c;我其实挺感慨的——这门语言的难点从来不是语法多&#xff0c;而是知识点之间的耦合太深…

2026/10/22 10:42:00 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介&#xff1a;亚太天能T109滑盖智能锁产品说明书以PDF格式发布&#xff0c;适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开&#xff0c;先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能&#xff0c;再给出完整安装步骤&…

2026/10/22 10:40:08 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历&#xff1a;翻开源码注释、论文摘要或者一份专业报告&#xff0c;每个字都认识&#xff0c;连在一起却像天书。想找人聊聊&#xff0c;身边要么没人懂&#xff0c;要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型&#xff0c;几秒钟之后&a…

2026/10/22 10:56:37 阅读更多 →

日新闻

周新闻

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

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

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

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

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

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

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

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

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

2026/10/22 5:12:39 阅读更多 →

月新闻

我发现了一个新思路:用 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/21 21:50:56 阅读更多 →
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/21 21:51:55 阅读更多 →
黑夜航拍船只数据集训练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/21 16:24:48 阅读更多 →