JVM生产环境问题定位与解决实战(六):总结篇——问题定位思路与工具选择策略

在这里插入图片描述

本文已收录于《JVM生产环境问题定位与解决实战》专栏,完整系列见文末目录

引言

在前五篇文章中,我们深入探讨了JVM生产环境问题定位与解决的实战技巧,从基础的jps、jmap、jstat、jstack、jcmd等工具,到JConsole、VisualVM、MAT的高级应用,再到Java飞行记录器(JFR)的强大功能,以及如何使用JMC进行JFR性能分析,最后介绍了Arthas这一不可错过的故障诊断利器。本篇文章作为总结篇,将梳理在面对JVM各种问题时我们的定位思路,并给出工具选择的策略。

一、JVM问题分类与核心场景

在定位问题前,需先明确问题类型。以下是JVM常见问题分类及典型特征:

1. 内存相关问题

  • 特征:内存泄漏、堆内存溢出(OOM)、元空间溢出、内存使用异常波动
  • 典型表现java.lang.OutOfMemoryError、JVM进程内存持续增长、GC频率异常

2. 性能瓶颈问题

  • 特征:响应延迟、吞吐量下降、CPU使用率异常
  • 典型表现:接口响应时间突增、TPS骤降、CPU 100%占用

3. 线程相关问题

  • 特征:线程阻塞、死锁、线程池异常、线程泄漏
  • 典型表现:线程数异常增长、接口无响应、java.util.concurrent包异常

4. GC相关问题

  • 特征:GC停顿时间过长、Full GC频繁、GC日志异常
  • 典型表现:JVM日志频繁出现Full GC、业务线程长时间被阻塞

5. 其他问题

  • 类加载异常、本地内存泄漏(Native Memory)、JVM崩溃(core dump)

二. JVM问题定位的一般思路

在生产环境中,JVM可能会遇到各种问题,比如CPU使用率过高、内存泄漏、线程死锁、性能瓶颈等。定位和解决这些问题的过程通常可以分为以下几个步骤:

  1. 监控与发现:通过操作系统提供的资源监控工具(如top、htop、free)、arthas、JVM自带工具(jps、jstat)或者搭建的监控系统(如Prometheus、Grafana)发现异常指标,如CPU飙升、内存溢出、系统宕机、gc异常等。
  2. 评估是否需要重启服务:根据问题的严重性和业务影响,决定是否立即重启服务以恢复业务。
  3. 快照捕获:使用合适的工具收集数据(如线程堆栈、堆转储文件、GC日志、应用日志等)。
  4. 数据分析:根据异常类型选择工具分析结果,确定问题的根源,例如代码缺陷、配置不当或资源竞争。
  5. 解决问题:采取针对性措施,如调整JVM参数、优化代码或修复逻辑错误。
  6. 验证与监控:解决问题后,持续监控系统,确保问题不再复现。

在这一过程中,选择合适的工具是关键。不同的工具适用于不同的场景和问题类型,接下来我们将对这些工具进行分类,并探讨如何根据具体问题选择合适的工具。

三. JVM工具分类

根据工具的使用方式和功能,我们可以将前五篇文章中介绍的工具分为以下几类:

  • 命令行工具 :

    • jps:查看JVM进程。
    • jmap:分析堆内存使用情况。
    • jstat:监控GC和JVM运行时统计信息。
    • jstack:查看线程堆栈。
    • jcmd:多功能命令行工具。
    • Arthas:在线诊断工具,支持线程分析、反编译等。
  • 图形化工具:

    • JConsole:实时监控JVM运行状态。
    • VisualVM:多功能的JVM监控和分析工具。
    • MAT(Memory Analyzer Tool):深入分析堆内存转储。
    • JMC(Java Mission Control):分析JFR记录的性能数据。
  • 性能分析工具:

    • JFR(Java Flight Recorder):内置于JDK的事件记录工具。
    • JMC:与JFR配合使用,分析性能瓶颈。

命令行工具适合在服务器上快速诊断,图形化工具适合本地深入分析,而性能分析工具则专注于性能调优。

四. 常见JVM问题及排查思路

以下是生产环境中常见的JVM问题,并针对每个问题提供可能的原因推测和实用的排查思路。

1 JVM进程突然消失

可能原因
  • OOM Killer:操作系统因内存不足触发Out-Of-Memory Killer,杀死了JVM进程。
  • JVM崩溃:JNI调用、本地代码bug或JVM本身的bug导致崩溃(会生成hs_err_pid.log文件)。
  • 外部干预:人为操作(如kill -9)或脚本误杀JVM进程。
排查思路
  1. 检查JVM日志:查看hs_err_pid<pid>.log文件(通常在工作目录下生成),分析崩溃堆栈。
  2. 检查系统日志:查看/var/log/messagesdmesggrep -i 'oom' /var/log/messages*grep -i 'sigterm' /var/log/syslog),确认是否被OOM Killer终止。
  3. 确认外部操作:检查服务器操作日志或运维记录,排除人为误操作。
  4. 启用JVM参数:添加-XX:+HeapDumpOnOutOfMemoryError生成堆转储文件;

2 内存使用率过高

可能原因
  • 内存泄漏:对象未被正确释放,堆内存持续增长。
  • 不合理的堆配置-Xmx-Xms设置过小或过大。
  • Metaspace溢出:类加载过多或动态代理使用不当。
  • 本地内存泄漏:JNI或NIO的Direct ByteBuffer未释放。
排查思路
  1. 监控内存使用
    • 使用jstat -gc查看堆内存和Metaspace使用情况。
    • 用Arthas的dashboard命令实时观察内存状态。
    • 通过JMC连接JVM,查看“Memory”视图中的堆使用趋势。
  2. 生成堆转储并分析内存泄漏
    • jmap -dump:live,format=b,file=heap.hprof <pid>或Arthas的heapdump /tmp/heap.hprof导出堆快照,结合MAT分析,通过Leak Suspects视图查看泄露疑点。或者选中 Retained Heap 最大的对象,右键选择 "List objects > with incoming references",查看有哪些对象引用了它。通过 "Path to GC Roots"(到 GC 根的路径)功能,找到该对象为什么没有被垃圾回收。选择 "excluding weak/soft references"(排除弱引用/软引用),以聚焦强引用路径。结合 MAT 的类名和引用链,推测可能的代码路径。
    • 用JFR记录(-XX:StartFlightRecording,settings=profile),在JMC的“Allocation”视图识别内存分配热点和泄漏对象。
  3. 检查GC日志
    • 开启JVM参数-XX:+PrintGCDetails-Xlog:gc*,分析GC频率和效果。
    • 结合Arthas的dashboard或JMC的“Garbage Collection”视图验证GC行为。
  4. 检查代码和类加载
    • 用Arthas的sc -d <className>检查类加载详情,排查Metaspace问题。
    • 用JFR的“Class Loading”事件和JMC分析类加载行为。
    • 用JMC的“Object Reference”视图追踪未释放对象的引用链,定位内存泄漏根源。
典型操作
jmap -dump:format=b,file=heap.hprof <pid>      # 生成堆转储
jstat -gcutil <pid> 1000                       # 每秒实时GC统计
jcmd <pid> VM.native_memory                    # 堆外内存分析(需开启NMT)

3 CPU使用率过高

可能原因
  • 死循环或高计算任务:代码中存在无限循环或复杂计算逻辑。
  • 线程竞争激烈:锁争用或线程池配置不当。
  • 频繁Full GC:垃圾回收过于频繁,占用CPU资源。
排查思路
  1. 定位高CPU线程
    • 使用top -H -p <pid>查看线程CPU占用,记录线程ID(转换为16进制)。
    • 用Arthas的thread命令列出线程并找到CPU占用最高的线程。
    • 用JFR(-XX:StartFlightRecording)在JMC的“CPU Load”或“Thread”视图中定位高CPU线程。
  2. 获取线程栈
    • 通过jstack <pid>生成线程调用栈,定位死循环或阻塞点。
    • 用Arthas的thread <threadId>查看具体线程堆栈。
    • 用JFR的“Method Profiling”在JMC中分析线程执行热点。
  3. 分析代码逻辑
    • 检查是否存在死循环、频繁GC或高负载任务。
  4. 检查GC行为
    • 开启GC日志(-XX:+PrintGCDetails),分析Full GC频率。
    • 结合MAT分析,Histogram视图中找到 Retained Heap 最大的对象,右键选择 "List objects > with incoming references",查看有哪些对象引用了它。通过 "Path to GC Roots"(到 GC 根的路径)功能,找到该对象为什么没有被垃圾回收。选择 "excluding weak/soft references"(排除弱引用/软引用),以聚焦强引用路径。结合 MAT 的类名和引用链,推测可能的代码路径。
    • 用Arthas的vmtool --action getInstances --className java.lang.Object检查对象创建情况。
    • 用JMC的“Garbage Collection”视图确认GC对CPU的影响。
典型操作
top -H -p <pid>                 # 查看线程CPU占用,记录下占用CPU最高的线程TID。
printf "%x\n" <TID>             #将TID转换为十六进制(Java堆栈中的线程ID是以十六进制表示的)
jstack <pid> > thread_dump.txt  # 抓取线程栈,在生成的thread_dump.txt中搜索对应的十六进制线程ID,找到该线程的堆栈信息。
---------------------------------------------------------------
thread -n 3                    # 显示最忙的3个线程(启动Arthas后执行)

4 线程死锁

可能原因
  • 锁顺序不当:多个线程以不同顺序获取多个锁。
  • 资源竞争:线程间对共享资源访问未正确同步。
  • 第三方库问题:依赖库中的锁使用不当。
排查思路
  1. 检测死锁
    • jstack <pid>输出末尾会明确提示Found one Java-level deadlock
    • 用Arthas的thread -b直接检测并输出死锁信息。
    • 用JFR记录(-XX:StartFlightRecording),在JMC的“Lock Instances”视图中检测锁竞争和死锁。
    • 使用JConsole或VisualVM的线程监控功能查看线程状态
  2. 分析死锁详情
    • jstack提示“Found one Java-level deadlock”,定位锁冲突点。
    • 用Arthas的thread <threadId>查看具体线程堆栈。
    • 用JMC的“Deadlock Detection”功能、JConsole或者VisualVM的线程视图展示锁冲突点和线程状态。
  3. 检查代码
    • 梳理加锁逻辑,确保锁获取顺序一致。
  4. 动态监控锁竞争
    • 用Arthas的monitor命令监控关键方法的执行频率和锁等待时间。
    • 用JMC的“Thread”视图分析锁等待时长和竞争热点,结合“Contended Locks”事件优化同步代码。

5 性能瓶颈

可能原因
  • I/O阻塞:数据库查询慢或文件操作耗时。
  • 锁等待:同步块或线程池任务排队。
  • GC暂停:STW(Stop-The-World)时间过长。
  • 网络延迟:外部服务响应慢。
排查思路
  1. 性能分析
    • 使用jvisualvm采样,定位耗时方法。
    • 用Arthas的trace <className> <methodName>追踪方法执行时间。
    • 用JFR(-XX:StartFlightRecording,settings=profile)记录,在JMC的“Method Profiling”视图定位耗时方法,结合“Latency”视图分析瓶颈来源。
  2. 检查线程状态
    • 通过jstack分析线程是否在WAITINGTIMED_WAITING状态。
    • 用Arthas的thread -state WAITING筛选等待线程。
    • 用JMC的“Thread”视图查看线程等待和阻塞详情。
  3. 优化GC
    • 调整-XX:+UseG1GC或 WiresharkCMS参数,减少暂停时间。
    • 用Arthas的dashboard监控GC状态。
    • 用JMC的“Garbage Collection”视图分析GC暂停时间。
  4. 外部依赖排查
    • 使用日志或Wireshark抓包分析网络耗时。
    • 用Arthas的watch <className> <methodName>观察方法入参和返回值。
    • 用JFR的“I/O”事件和JMC分析文件或网络操作耗时。
典型操作
# 使用Arthas的trace命令追踪方法执行时间。
trace com.ExampleController getUserInfo "#cost > 200"# 输出结果
`---[213.3576ms] com.ExampleController:getUserInfo()+---[212.12ms] com.UserService:queryFromDB() # 发现DB查询耗时|   `---[210.45ms] org.mybatis.spring.SqlSessionTemplate:selectOne()`---[1.2ms] com.Utils:maskPhoneNumber() watch com.example.Service::handleRequest '{args,requestTime}'

6 GC问题

典型表现
  • 频繁Full GCjstat -gcutil中FGC列快速增加
  • GC停顿过长:通过-Xlog:gc*日志观察暂停时间
  • 晋升失败:年轻代对象过快进入老年代
可能原因
  • GC频率过高:对象创建速度快,年轻代空间不足。
  • Full GC频繁:老年代填满,触发长时间STW。
  • GC配置不当:垃圾回收器选择或参数设置不合理。
排查思路
  1. 开启GC日志并实时监控
    • 配置-XX:+PrintGCDetails -Xlog:gc*,分析GC耗时和效果。
    • 用Arthas的dashboard实时查看GC状态。
    • 用JMC的“Garbage Collection”视图分析GC次数和暂停时间。
  2. 监控内存分区
    • jstat -gcutil <pid>观察Eden、Survivor、Old区使用率。
    • 用Arthas的ognl '@java.lang.management.ManagementFactory@getGarbageCollectorMXBeans()'获取GC统计。
    • 用JFR的“Memory”视图和JMC分析内存分配与GC行为。
  3. 调整堆大小并分析GC根因
    • 根据业务负载调整-Xmx-Xms-XX:NewRatio
    • 用Arthas的heapdump生成堆快照分析老年代对象。
    • 用JFR(-XX:StartFlightRecording,dump-on-exit=true)生成堆快照,在JMC的“Allocation”视图定位高频分配对象,优化代码减少GC压力。
  4. 选择合适GC算法
    • 低延迟场景用G1,高吞吐量用Parallel GC。
    • 结合JMC的“GC Times”和“GC Pause”分析优化参数。
    • 调整堆大小-Xms-Xmx设为相同值,避免动态扩容

五. 先重启还是先排查的选择

在生产环境中遇到JVM问题时,开发者往往面临一个抉择:是立即重启服务以快速恢复,还是先排查问题以避免复发?以下是选择依据及后续排查措施。

判断依据

  • 问题严重性
    • 如果服务完全不可用(如JVM进程消失或响应超时),且影响核心业务,优先考虑重启以恢复服务。
    • 如果问题仅表现为性能下降或间歇性异常,可先尝试在线排查。
  • 数据丢失风险
    • 重启可能导致内存中未持久化的数据丢失,需评估业务影响。
  • 复现难度
    • 如果问题难以复现,重启前尽量收集现场数据(如堆转储、线程栈、JFR记录)。

必须立即恢复服务的措施

若必须马上恢复服务,可采取以下措施在不中断排查的情况下继续分析问题:

  1. 收集关键数据后重启
    • 在重启前快速执行jmap -dump:live,format=b,file=heap.hprof <pid>生成堆转储。
    • jstack <pid>抓取线程栈。
    • 确保JFR已启用(-XX:StartFlightRecording,dumponexit=true),保存退出时的记录文件。
  2. 流量复制到测试环境
    • 配置流量镜像工具(如TCPdump或服务网格的Sidecar),将生产流量复制到测试环境。
    • 在测试环境回放流量,观察是否复现问题。
  3. 在测试环境复现
    • 根据生产环境的日志、请求参数和负载特征,构造测试用例。
    • 在测试环境启用JFR(-XX:StartFlightRecording)和Arthas,模拟问题场景。
  4. 开启新节点并隔离问题节点
    • 部署新JVM节点接管流量,保持问题节点运行但不接收新请求。
    • 在隔离节点上用Arthas(dashboardthread)或JMC实时分析,避免影响服务。

六. 工具选择指南

在实际工作中,面对JVM问题时,可以参考以下指南选择工具:

  1. 快速诊断
    • 在服务器上使用命令行工具(如jstack、jmap、Arthas)快速获取初步信息。
    • 示例:CPU过高时,运行jstack > stack.txt查看线程堆栈。
  2. 深入分析
    • 将堆转储文件或JFR记录下载到本地,使用MAT、JMC等工具进行详细分析。
    • 示例:分析内存泄漏时,用MAT打开jmap生成的heap.hprof文件。
  3. 实时监控
    • 使用JConsole或VisualVM观察JVM的实时状态,适合初步排查。
    • 示例:连接到远程JVM,监控内存和线程变化。
  4. 性能分析
    • 使用JFR和JMC进行全面性能分析,适合长期优化。
    • 示例:运行JFR记录1分钟数据,用JMC查看方法耗时分布。
  5. 在线诊断
    • 在不重启JVM的情况下,使用Arthas进行动态排查。
    • 示例:怀疑某方法有问题,用jad com.example.MyClass反编译代码。

JVM问题的排查需要综合运用工具、日志和代码分析。传统工具如jps(查看进程)、jmap(堆转储)、jstack(线程转储)、jstat(GC监控),结合Arthas的动态诊断和JMC/JFR的深度分析能力,可以覆盖内存泄漏、锁竞争、性能瓶颈和GC问题等多种场景。工具之间还可以组合使用。例如,先用jstack找到问题线程,再用Arthas的jad反编译相关类;或者用JFR记录数据,再用JMC可视化分析。

在生产环境中,建议提前配置监控日志,部署Arthas并启用JFR,遇到问题时根据严重性选择重启或排查策略,确保服务稳定性和问题根因分析兼顾。希望本文的排查思路能为您解决JVM问题提供实用指导!

附录:系列目录

  1. JVM生产环境问题定位与解决实战(一):掌握jps、jmap、jstat、jstack、jcmd等基础工具
  2. JVM生产环境问题定位与解决实战(二):JConsole、VisualVM到MAT的高级应用
  3. JVM生产环境问题定位与解决实战(三):揭秘Java飞行记录器(JFR)的强大功能
  4. JVM生产环境问题定位与解决实战(四):使用JMC进行JFR性能分析指南
  5. JVM生产环境问题定位与解决实战(五):Arthas——不可错过的故障诊断利器
  6. ➡️ 当前:JVM生产环境问题定位与解决实战(六):总结篇——问题定位思路与工具选择策略

🔥 下篇预告:《JVM生产环境问题定位与解决实战(七):真实案例解剖——从工具链到思维链的完全实践》
🚀 关注作者,获取实时更新通知!有问题欢迎在评论区交流讨论~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/75375.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【5090d】配置运行和微调大模型所需基础环境【一】

RuntimeError: Failed to import transformers.integrations.bitsandbytes because of the following error (look up to see its traceback): No module named triton.ops 原因&#xff1a;是因为在导入 transformers.integrations.bitsandbytes 时缺少必要的依赖项 triton.op…

华为交换综合实验——VRRP、MSTP、Eth-trunk、NAT、DHCP等技术应用

一、实验拓扑 二、实验需求 1,内网Ip地址使用172.16.0.0/16分配 2,sw1和SW2之间互为备份 3, VRRP/STP/VLAN/Eth-trunk均使用 4,所有Pc均通过DHCP获取IP地址 5,ISP只能配置IP地址 6,所有电脑可以正常访问IsP路由器环回 三、需求分析 1、设备连接需求 二层交换机&#xff08;LS…

DeepSeek 开源的 3FS 如何?

DeepSeek 3FS&#xff08;Fire-Flyer File System&#xff09;是一款由深度求索&#xff08;DeepSeek&#xff09;于2025年2月28日开源的高性能并行文件系统&#xff0c;专为人工智能训练和推理任务设计。以下从多个维度详细解析其核心特性、技术架构、应用场景及行业影响&…

Qt实现HTTP GET/POST/PUT/DELETE请求

引言 在现代应用程序开发中&#xff0c;HTTP请求是与服务器交互的核心方式。Qt作为跨平台的C框架&#xff0c;提供了强大的网络模块&#xff08;QNetworkAccessManager&#xff09;&#xff0c;支持GET、POST、PUT、DELETE等HTTP方法。本文将手把手教你如何用Qt实现这些请求&a…

echarts+HTML 绘制3d地图,加载散点+散点点击事件

首先&#xff0c;确保了解如何本地引入ECharts库。 html 文件中引入本地 echarts.min.js 和 echarts-gl.min.js。 可以通过官网下载或npm安装&#xff0c;但这里直接下载JS文件更简单。需要引入 echarts.js 和 echarts-gl.js&#xff0c;因为3D地图需要GL模块。 接下来是HTM…

深度剖析 MySQL 与 Redis 缓存一致性:理论、方案与实战

在当今的互联网应用开发中&#xff0c;MySQL 作为可靠的关系型数据库&#xff0c;与 Redis 这一高性能的缓存系统常常协同工作。然而&#xff0c;如何确保它们之间的数据一致性&#xff0c;成为了开发者们面临的重要挑战。本文将深入探讨 MySQL 与 Redis 缓存一致性的相关问题&…

DAO 类的职责与设计原则

1. DAO 的核心职责 DAO&#xff08;Data Access Object&#xff0c;数据访问对象&#xff09;的主要职责是封装对数据的访问逻辑&#xff0c;但它与纯粹的数据实体类&#xff08;如 DTO、POJO&#xff09;不同&#xff0c;也与 Service 业务逻辑层不同。 DAO 应该做什么&…

【Kubernetes】如何使用 kubeadm 搭建 Kubernetes 集群?还有哪些部署工具?

使用 kubeadm 搭建 Kubernetes 集群是一个比较常见的方式。kubeadm 是 Kubernetes 提供的一个命令行工具&#xff0c;它可以简化 Kubernetes 集群的初始化和管理。下面是使用 kubeadm 搭建 Kubernetes 集群的基本步骤&#xff1a; 1. 准备工作 确保你的环境中有两台或更多的机…

Pycharm(十二)列表练习题

一、门和钥匙 小X在一片大陆上探险&#xff0c;有一天他发现了一个洞穴&#xff0c;洞穴里面有n道门&#xff0c; 打开每道门都需要对应的钥匙&#xff0c;编号为i的钥匙能用于打开第i道门&#xff0c; 而且只有在打开了第i(i>1)道门之后&#xff0c;才能打开第i1道门&#…

在未归一化的线性回归模型中,特征的尺度差异可能导致模型对特征重要性的误判

通过数学公式来更清晰地说明归一化对模型的影响&#xff0c;以及它如何改变特征的重要性评估。 1. 未归一化的情况 假设我们有一个线性回归模型&#xff1a; y β 0 β 1 x 1 β 2 x 2 ϵ y \beta_0 \beta_1 x_1 \beta_2 x_2 \epsilon yβ0​β1​x1​β2​x2​ϵ 其…

JS—页面渲染:1分钟掌握页面渲染过程

个人博客&#xff1a;haichenyi.com。感谢关注 一. 目录 一–目录二–页面渲染过程三–DOM树和渲染树 二. 页面渲染过程 浏览器的渲染过程可以分解为以下几个关键步骤 2.1 解析HTML&#xff0c;形成DOM树 浏览器从上往下解析HTML文档&#xff0c;将标签转成DOM节点&#…

niuhe插件, 在 go 中渲染网页内容

思路 niuhe 插件生成的 go 代码是基于 github.com/ma-guo/niuhe 库进行组织管理的, niuhe 库 是对 go gin 库的一个封装&#xff0c;因此要显示网页, 可通过给 gin.Engine 指定 HTMLRender 来实现。 实现 HTMLRender 我们使用 gitee.com/cnmade/pongo2gin 实现 1. main.go …

openEuler24.03 LTS下安装HBase集群

前提条件 安装好Hadoop完全分布式集群&#xff0c;可参考&#xff1a;openEuler24.03 LTS下安装Hadoop3完全分布式 安装好ZooKeeper集群&#xff0c;可参考&#xff1a;openEuler24.03 LTS下安装ZooKeeper集群 HBase集群规划 node2node3node4MasterBackup MasterRegionServ…

LVGL移植说明

https://www.cnblogs.com/FlurryHeart/p/18104596 参考&#xff0c;里面说明了裸机移植以及freeRTOS系统移植。 移植到linux https://blog.csdn.net/sunchao124/article/details/144952514

ubuntu虚拟机裁剪img文件系统

1. 定制文件系统前期准备 将rootfs.img文件准备好&#xff0c;并创建target文件夹2. 挂载文件系统 sudo mount rootfs.img target #挂载文件系统 sudo chroot target #进入chroot环境3. 内裁剪文件系统 增删裁剪文件系统 exit #退出chroot环境 sudo umount target…

esp826601s固件烧录方法(ch340+面包板)

esp826601s固件烧录方法&#xff08;ch340面包板&#xff09; 硬件 stm32f10c8t6&#xff0c;esp826601s,面包板&#xff0c;ch340(usb转ttl),st_link&#xff08;供电&#xff09; 接线 烧录时&#xff1a; stm32f10c8t6&#xff1a;gnd->负极&#xff0c; 3.3->正极…

Servlet 点击计数器

Servlet 点击计数器 引言 Servlet 是 Java 企业版&#xff08;Java EE&#xff09;技术中的一种服务器端组件&#xff0c;用于处理客户端请求并生成动态内容。本文将详细介绍如何使用 Servlet 实现一个简单的点击计数器&#xff0c;帮助读者了解 Servlet 的基本用法和原理。 …

LangChain vs. LlamaIndex:深入对比与实战应用

目录 引言LangChain 与 LlamaIndex 概述 什么是 LangChain&#xff1f;什么是 LlamaIndex&#xff1f;两者的核心目标与适用场景 架构与设计理念 LangChain 的架构设计LlamaIndex 的架构设计关键技术差异 核心功能对比 数据连接与处理查询与检索机制上下文管理能力插件与扩展性…

【Java中级】10章、内部类、局部内部类、匿名内部类、成员内部类、静态内部类的基本语法和细节讲解配套例题巩固理解【5】

❤️ 【内部类】干货满满&#xff0c;本章内容有点难理解&#xff0c;需要明白类的实例化&#xff0c;学完本篇文章你会对内部类有个清晰的认知 &#x1f495; 内容涉及内部类的介绍、局部内部类、匿名内部类(重点)、成员内部类、静态内部类 &#x1f308; 跟着B站一位老师学习…

内容中台:驱动多渠道营销的关键策略

在数字营销快速发展的今天&#xff0c;企业需要在多个渠道&#xff08;网站、社交媒体、移动应用等&#xff09;上同步管理内容。尽管网站仍是品牌展示的核心&#xff0c;但信息分散、多平台重复创建内容的问题&#xff0c;让营销人员面临巨大的管理挑战。 内容中台&#xff0…