第9章:OpenJDK堆分代与 Serial/Parallel GC 基础
1. 项目背景业务场景某电商的每日推荐批处理任务每天凌晨 2 点运行处理约 2000 万条用户行为数据计算推荐模型并写入缓存。该任务一直稳定运行在 JDK 8 的 Parallel GC 下耗时约 45 分钟。团队为了使用虚拟线程特性将 JDK 升级到 21JVM 参数原封不动搬过来。结果批处理耗时从 45 分钟飙升至 70 分钟运维排查发现 GC 停顿时间占比从 3% 变为 18%。痛点GC 算法选型的惯性团队使用了 6 年的 Parallel GC 参数模板-XX:UseParallelGC从未思考它是否适合当前负载。JDK 21 的默认 GC 已改为 G1团队却顺手沿用旧参数——Parallel GC 在追求吞吐的批处理场景没问题但年轻代回收的停顿时间随堆增大而线性增长。分代假说的滥用很多人背口诀大多数对象朝生夕死但对其落地的 Eden/Survivor/Old 之间的晋升机制一知半解。比如不清楚对象何时从 Eden 晋升到 Survivor“经过几次 Minor GC 后进入 Old Gen”大对象直接分配在 Old Gen的精确规则。GC 日志的读不懂运维拿到-Xlog:gc*的输出后只能看有没有 Full GC不知道如何从日志中分析分配速率、晋升阈值、停顿分布。本章从为什么要分代出发用实验数据验证弱分代假说深入 Serial GC 和 Parallel GC 的工作原理并在最后用 Unified Logging 绘制分配速率-停顿曲线建立一套读 GC 日志的系统方法。2. 项目设计半夜两点小胖被 PagerDuty 叫醒——批处理任务超时了。小胖大师为什么同样的代码、同样的参数JDK 8 跑 45 分钟JDK 21 跑 70 分钟不是说 Java 越升级越快吗大师看了一下 GC 日志你们用了-XX:UseParallelGC对吧JDK 8 的默认堆大小和 JDK 21 不一样同一台机器的默认 GC 线程数也可能不同。但最关键的是——你不应该用 Parallel GC跑一个会产生大量长期存活对象的批处理任务。咱们先退一步从为什么 GC 要分代聊起。你知道弱分代假说Weak Generational Hypothesis吗这是所有分代 GC 的理论基石绝大多数对象朝生夕死只有少数长命百岁。来自实际测量IBM 的研究98% 的对象在分配后很快变成垃圾只有 2% 的对象能存活超过一次 GC。这就好比食堂的纸巾——每顿饭用一张用完立刻扔掉朝生夕死但盛菜的盘子会反复用一整天长命百岁。分代 GC 的策略┌──────────────────────────────────────┐ │ 堆 (Heap) │ │ ┌─────────────────────────────────┐ │ │ │ 新生代 (Young Generation) │ │ │ │ ┌──────┬───────┬───────┐ │ │ │ │ │ Eden │ S0 │ S1 │ │ │ ← Minor GC │ │ │ (8) │ (1) │ (1) │ │ │ (频繁、快速) │ │ └──────┴───────┴───────┘ │ │ │ │ 默认比例 Eden:S0:S1 8:1:1 │ │ │ └─────────────────────────────────┘ │ │ ┌─────────────────────────────────┐ │ │ │ 老年代 (Old Generation) │ │ ← Major GC / Full GC │ │ 存活多次 GC 的对象 │ │ (不频繁、较慢) │ └─────────────────────────────────┘ │ └──────────────────────────────────────┘技术映射Eden ↔ 食堂的用餐区人来人往大部分盘子很快回收Survivor ↔ 食堂的暂存区还没决定要不要长期保留Old ↔ 厨房的储物柜长期使用的锅碗瓢盆。小白那对象是怎么从 Eden 升到 Old 的什么叫晋升大师晋升规则有精确的条件年龄晋升对象在 Survivor 区每经历一次 Minor GC 而没有被回收年龄 1。当年龄超过-XX:MaxTenuringThreshold默认 15晋升到 Old。动态年龄判断如果 Survivor 区中同龄对象的大小超过了 Survivor 区的一半年龄 ≥N 的对象直接晋升——不管MaxTenuringThreshold是多少。空间担保如果 Survivor 区放不下了触发 Minor GC 后存活对象太多对象绕过 Survivor 直接进入 Old。大对象直通超过-XX:PretenureSizeThreshold的对象直接在 Old 分配仅 Serial/Parallel 有效G1 不适用。// 对象的逃亡之旅byte[]datanewbyte[1024*1024*10];// 10MB 大对象// → 如果 PretenureSizeThreshold1MB → 直接进入 Old GenListbyte[]cachenewArrayList();for(inti0;i100;i){cache.add(newbyte[1024]);// 小对象在 Eden 分配}System.gc();// 触发 GC → cache 中的对象被标记为存活 → 进入 Survivor// 15 次 GC 后 → 这些对象晋升到 Old Gen技术映射对象在 Eden ↔ 新生婴儿在育婴室Survivor ↔ 幼儿园一次一次年级升级Old ↔ 成年人社会养老也要在这里。小胖那 Serial GC 和 Parallel GC 有什么区别为什么一个叫串行一个叫并行大师名字起得很直白——Serial就是单线程做 GCParallel就是多线程做 GC。Serial GC(-XX:UseSerialGC)年代最久远的 GC年轻代和老年代回收都用单线程。适合客户端应用和单核 CPU 环境。当应用暂停时只做 GC没有任何业务线程在运行。Parallel GC(-XX:UseParallelGC)JDK 8 及之前的服务端默认 GC。年轻代回收用多线程并行老年代默认也是多线程-XX:UseParallelOldGC。追求的是吞吐量——单位时间内业务运行时间占比最大停顿次数少但单次停顿时间长。两者的核心差异特性Serial GCParallel GC年轻代回收线程1-XX:ParallelGCThreadsN默认CPU 核数老年代回收线程1多线程目标最小化内存和 CPU 开销最大化吞吐量吞吐 业务时间 / 总时间适用场景客户端、单核、100MB 堆批处理、科学计算、对停顿不敏感的服务优点实现简单无线程切换开销多核机器上吞吐极高缺点大堆停顿时间长停顿随堆增大而线性增长延迟不可控技术映射Serial GC ↔ 办公室只有一个保洁阿姨一个人打扫整个办公室Parallel GC ↔ 一个保洁团队8 个人同时打扫不同区域。小白等一下你刚才说 JDK 21 的默认 GC 是 G1那 Serial 和 Parallel 还有学习的必要吗大师必须学原因有三Serial/Parallel 是理解 GC 的基础许多 GC 概念Eden/Survivor/Old、晋升、卡表、跨代引用在 Serial/Parallel 中最纯粹、最直观。G1 和 ZGC 是这些概念上的演进不是推翻。Serial GC 是极端场景的救命稻草当你的堆只剩 64MB、系统只剩 1 个核时Serial GC 是唯一的选择。容器化时代这并不罕见。Parallel GC 在特定场景仍然最优批处理、离线计算——这些对停顿不敏感但对吞吐敏感的场景Parallel GC 至今仍然是吞吐最高的选择。3. 项目实战3.1 环境准备组件版本用途JDKOpenJDK 21运行 GC 体验程序GC 日志分析GCViewer / gceasy.io可视化 GC 日志压测工具JMH 或手写测试模拟不同分配模式3.2 分步实现步骤一观察 Young GC 的完整生命周期目标创建大量短命对象 少量长命对象用 GC 日志验证对象晋升路径。// YoungGCDemo.java —— 观察新生代回收importjava.util.ArrayList;importjava.util.List;publicclassYoungGCDemo{// 每 1MB 1024 * 1024 / 4 262144 个 intprivatestaticfinalint_1MB1024*1024/4;publicstaticvoidmain(String[]args)throwsException{System.out.println(PID: ProcessHandle.current().pid());System.out.println(开始分配观察 Young GC...\n);Listint[]youngRefsnewArrayList();// 存活对象会被晋升// 第一轮分配填满 Edenfor(inti0;i30;i){int[]arrnewint[_1MB];// 约 4MB per allocationif(i5)youngRefs.add(arr);// 前 5 个存活System.out.println(分配第 (i1) 个 4MB 数组);}System.out.println(第 1 次 Young GC 应该发生了\n);Thread.sleep(1000);// 第二轮分配触发晋升for(inti0;i30;i){int[]arrnewint[_1MB];if(i3)youngRefs.add(arr);System.out.println(分配第 (i1) 个 4MB 数组);}System.out.println(第 2 次 Young GC部分对象应晋升到 Old\n);Thread.sleep(3000);System.out.println(youngRefs 大小: youngRefs.size());}}# 用 Serial GC 运行Eden80M, S0S110M, Old100Mjavac YoungGCDemo.javajava-XX:UseSerialGC\-Xms200m-Xmx200m\-Xmn100m\-XX:SurvivorRatio8\-XX:PrintGCDetails\-XX:PrintGCDateStamps\-Xlog:gc*:fileserial_gc.log\YoungGCDemo# 查看 GC 日志catserial_gc.log日志解读[2026-01-01T12:00:00.0000800] GC(0) Pause Young (Allocation Failure) [DefNew: 81920K-10240K(92160K)] DefNew是Serial的年轻代实现 对象从81920K降到10240K → 回收了约70MB步骤二对比 Serial vs Parallel 的吞吐量目标同一个分配密集程序分别用 Serial 和 Parallel 运行对比吞吐量差异。// GCBenchmark.java —— 对比 GC 吞吐量publicclassGCBenchmark{privatestaticfinalint_1MB1024*1024/4;publicstaticvoidmain(String[]args)throwsException{longstartTimeSystem.currentTimeMillis();inttotalWork0;// 模拟批处理分配大量对象并进行计算for(intround0;round10;round){int[][]datanewint[50][_1MB];// 50 * 4MB 200MB per round// 模拟计算for(inti0;idata.length;i){for(intj0;j1000;j){data[i][j]i*j;}totalWorkdata[i][0];}// 大部分数组在循环结束后变成垃圾朝生夕死if(round%20){System.out.println(Round round 完成);}}longendTimeSystem.currentTimeMillis();longelapsedendTime-startTime;System.out.println(总耗时: elapsed ms);System.out.println(总工作量: totalWork (防编译器优化));}}# 编译javac GCBenchmark.javaecho Serial GC timejava-XX:UseSerialGC-Xms512m-Xmx512m\-Xlog:gc*:fileserial_bench.log GCBenchmarkechoecho Parallel GC timejava-XX:UseParallelGC-Xms512m-Xmx512m\-XX:ParallelGCThreads4\-Xlog:gc*:fileparallel_bench.log GCBenchmarkechoecho 对比 GC 日志统计 echo--- Serial GC 统计 ---grep-cPause Youngserial_bench.logecho--- Parallel GC 统计 ---grep-cPause Youngparallel_bench.log典型结果对比4 核虚拟机指标Serial GCParallel GC总耗时~8500 ms~5200 msGC 停顿次数42 次38 次总 GC 时间~2200 ms~1200 ms吞吐量~74%~81%步骤三绘制分配速率-停顿曲线目标通过改变分配速率观察 GC 停顿之间的关系。// AllocationRateDemo.java —— 分配速率与 GC 停顿的关系publicclassAllocationRateDemo{publicstaticvoidmain(String[]args)throwsInterruptedException{System.out.println(PID: ProcessHandle.current().pid());System.out.println(分配速率 (MB/s) | 每轮分配 MB);int[]sizes{1,2,5,10,20,50,100};// 每秒分配不同大小的内存for(intsizeMB:sizes){intsizesizeMB*1024*1024/8;// 字节数组大小long8 byteslongstartTimeSystem.nanoTime();longbytesAllocated0;int[]keepRefsnewint[10];// 保留 10 个引用其余可回收// 分配 2 秒while(System.nanoTime()-startTime2_000_000_000L){long[]arrnewlong[size];// 快速分配keepRefs[(int)(Math.random()*10)](int)arr[0];// 随机保留引用bytesAllocatedsize*8L;}doubleratebytesAllocated/(1024.0*1024.0)/2.0;// MB/sSystem.out.printf( %3d MB | %.1f MB/s%n,sizeMB,rate);System.gc();// 清理后重新开始下一轮Thread.sleep(2000);}}}# 用不同 GC 运行并记录日志java-XX:UseSerialGC-Xms256m-Xmx256m\-Xlog:gc*info:filealloc_rate_serial.log::filecount0\AllocationRateDemo# 分析日志中的停顿时间与分配速率的关系grepPausealloc_rate_serial.log|awk{print $NF}|head-20步骤四Serial GC 的 Full GC 触发条件演示目标制造一个老年代满的场景触发 Full GC。// FullGCDemo.java —— 触发老年代 Full GCimportjava.util.ArrayList;importjava.util.List;publicclassFullGCDemo{privatestaticfinalint_1MB1024*1024/4;publicstaticvoidmain(String[]args)throwsException{System.out.println(PID: ProcessHandle.current().pid());System.out.println(制造 Full GC 场景...);Listint[]liveListnewArrayList();// 持续分配长命对象逐渐填满老年代for(inti0;i100;i){liveList.add(newint[_1MB*10]);// 40MB per objectSystem.out.println(已分配 (i1) 个 40MB 对象 → 约 ((i1)*40) MB);Thread.sleep(200);}// 当 Old Gen 满时会触发 Full GC// Full GC 将尝试回收如果 liveList 持有所有引用则无法回收 → OOM}}# 堆256MB其中老年代约 160MB-Xmn100m → 新生代100MB 老年代156MBjava-XX:UseSerialGC-Xms256m-Xmx256m-Xmn100m\-XX:PrintGCDetails\-Xlog:gc*info:filefullgc_demo.log\FullGCDemo# 在日志中查找 Full GCgrepFull GCfullgc_demo.log可能遇到的坑-Xmn设置过大新生代设太大→老年代空间不够→对象频繁提前晋升→ Full GC 频繁。新生代大小建议先测量再设置不要盲设。Survivor 空间太小如果 Survivor 空间放不下 Minor GC 后存活的对象 → 对象直接晋升 Old叫过早晋升→ Old 快速被填充 → Full GC 增多。System.gc()会触发 Full GC在生产代码中禁用System.gc()调用——用-XX:DisableExplicitGC。Parallel GC 的 GC 线程数默认ParallelGCThreads CPU 核数。在容器中如果 limit 是 2C但宿主机 64C → JVM 可能创建 64 个 GC 线程上下文切换开销巨大。JDK 8u191 的容器感知会纠正这个行为。3.3 测试验证GC 验证矩阵验证点命令预期观察Young GC 触发分配填满 Eden →DefNew...日志Minor GC 后 Eden 清空存活对象→Survivor对象晋升到 Old分配后观察 Old Gen 使用量增长Old Gen 中的used值增大Serial vs Parallel 吞吐分别跑 GCBenchmarkParallel 总时间更短多核Full GC 触发分配堆满对象且持有引用Full GC 出现且 Old Gen 无法回收大对象直接进 Old分配 PretenureSizeThreshold 的对象GC 日志显示直接在 Tenured 分配#!/bin/bashecho 完整 GC 验证 echo1. Young GC 演示java-XX:UseSerialGC-Xms128m-Xmx128m-Xmn64m\-Xlog:gc*info-XX:PrintGC\YoungGCDemo21|grep-EPause|GCechoecho2. Full GC 演示java-XX:UseSerialGC-Xms128m-Xmx128m-Xmn32m\-Xlog:gc*info FullGCDemo21|grepFull GCechoecho3. 大对象直通 Old Genjava-XX:UseSerialGC-Xms128m-Xmx128m\-XX:PretenureSizeThreshold1048576\-Xlog:gc*info-cp.\-cbyte[] bnew byte[10*1024*1024]; Thread.sleep(5000);\21|grep-itenured\|old4. 项目总结4.1 优点与缺点维度优点缺点分代模型大幅减少了 GC 每次需要扫描的对象数量只扫新生代跨代引用需要维护卡表增加 minor GC 开销Serial GC实现极简、无 GC 线程调度开销适合小堆和单核大堆停顿时间不可接受200MB 堆停顿可达 2-3 秒Parallel GC多核机器上吞吐极高对非交互式批处理最优停顿时间随堆大小线性增长无法保证延迟上限Unified Logging统一的-Xlog标签体系日志结构化、可检索GC 标签多gcheap、gcergo、gcage…初学容易混淆晋升机制灵活的动态年龄判断和空间担保动态年龄判断在边缘情况下行为非确定性——同一程序在不同 JVM 版本间晋升行为可能不同4.2 适用场景Serial GC 适用客户端桌面应用、内存 100MB 的微服务、嵌入式开发板如 Raspberry Pi。Parallel GC 适用批处理、ETL 数据处理、科学计算——只要对停顿不敏感Parallel GC 的吞吐无人能敌。学习 GC 基础Serial 和 Parallel 的简单实现是理解 G1/ZGC 等复杂 GC 的必经之路。容器极简环境单核 128MB 内存的容器中Serial GC 是唯一可靠的选择。GC 日志训练用 Serial/Parallel 的清洁日志学习 GC 日志解读标签少、逻辑清晰。不适用场景交互式 Web 服务要求 P99 100ms——Serial/Parallel 无法保证低延迟应选 G1 或 ZGC。大堆 4GB——Parallel GC 的停顿可达 5-10 秒不可接受。混部环境——Serial/Parallel 的 Stop-The-World 会暂停所有业务线程严重影响多租户体验。4.3 注意事项类型详细说明MaxTenuringThreshold默认值 15 是最大值4 bits 存储但实际晋升由动态年龄判断决定——不要以为设 0 就能让所有对象不进 OldSurvivorRatioEden:S0:S1 8:1:1 是默认值。如果 Survivor 太小→过早晋升太大→ Eden 太小→ GC 频繁PretenureSizeThreshold仅对 Serial 和 Parallel GC 有效G1 有独立的-XX:G1HeapRegionSize决定大对象阈值AdaptiveSizePolicyParallel GC 默认开启自适应的新生代大小调整——-XX:-UseAdaptiveSizePolicy可关闭此行为4.4 常见踩坑经验案例 1Survivor 区溢出导致名存实亡的晋升某缓存服务用 Parallel GC配置-XX:MaxTenuringThreshold15期望对象在 Survivor 区待足够久才晋升。但生产上 GC 日志显示大量对象在 1-2 次 GC 后就晋升了。根因Survivor 区太小默认 SurvivorRatio8S0S11/10 堆存活对象超过了 S0/S1 容量→ 触发空间担保直接晋升。修复调大 SurvivorRatio 或者增大整体-Xmn。案例 2Parallel GC 的 GC 线程数爆炸微服务部署在 K8s 中Pod 限制 2C/4Gi但jstat显示 GC 线程数为 32——等于宿主机物理核数。根因JDK 8u191 之前的版本不感知容器 cgroup 限制ParallelGCThreads读的是物理机的 CPU 核数。修复升级到 JDK 8u191 或显式设置-XX:ParallelGCThreads2。案例 3大对象直接进 Old 造成 Full GC 螺旋某数据导入工具用byte[10MB]数组读取文件并解析。PretenureSizeThreshold设为 1MB所有文件缓冲区直接分配在老年代。1000 个文件导入后 Old Gen 满 → Full GC → 老年代释放部分 → 继续导入 → 再次 Full GC → “Full GC 螺旋”。根因大对象不该走堆——应用ByteBuffer.allocateDirect()堆外分配或按批次流式处理而非全量加载。4.5 思考题进阶题MaxTenuringThreshold和动态年龄判断有什么区别如果 Survivor 区中所有同龄对象总大小超过了 Survivor 区 50%年龄多少的对象会被直接晋升请通过修改 GC 日志级别-Xlog:gcagetrace来验证你的结论。实战题你的服务目前使用-XX:UseParallelGC堆大小 8GB。用户投诉偶发性响应超时2-3 秒。怀疑是 GC 停顿造成的。请设计一个方法不依赖第三方工具在线上验证停顿时间是否贡献了超时的大头并给出切换到 G1 GC 的参数推荐。答案提示思考题 1 答案见本章晋升机制部分思考题 2 答案见第 20 章 G1 GC 原理与调优。下一章预告第 10 章将系统梳理 Java 的异常体系——Throwable家族、受检/非受检争议、hs_err_pid日志解读以及一份可用于生产的线上异常分级与处置 SOP。延伸阅读与资源Redis 8 实战精讲从 CRUD 到源码构建高可用缓存系统Redis 实战修炼与原理进阶Python 3实战精进从脚本到高并发订单引擎MongoDB 实战进阶与内核修炼python入门Rquests从菜鸟脚本到企业级SDK的网络实战圣经Milvus向量数据库实战修炼从 0 到 1精通向量检索与生产落地后端工程师的 AI 转型第一课Ollama 与私有化大模型实战10倍开发者的 Dify 魔法书从零构建全栈 AI 应用后端工程师转型AI第一课-Ollama 与私有化大模型实战大型语言模型(LLM) vLLM 高性能推理落地实战Agent开发之LlamaIndex 实战修炼与源码进阶大语言模型Transformers 实战修炼与源码剖析

相关新闻

gh_mirrors/au/auto-submit配置详解:从学校信息到邮件推送,新手也能轻松搞定

gh_mirrors/au/auto-submit配置详解:从学校信息到邮件推送,新手也能轻松搞定

gh_mirrors/au/auto-submit配置详解:从学校信息到邮件推送,新手也能轻松搞定 【免费下载链接】auto-submit 今日校园自动提交疫情上报,通用 项目地址: https://gitcode.com/gh_mirrors/au/auto-submit 今日校园自动提交疫情上报工具&a…

2026/10/15 3:10:11 阅读更多 →
降温约朋友搓火锅,试了6家南昌人气火锅店太满足

降温约朋友搓火锅,试了6家南昌人气火锅店太满足

一、降温季吃南昌人气火锅店,核心关注哪几个维度?从火锅消费体验的核心维度出发,降温季选择南昌人气火锅店,可重点参考锅底工艺、食材品质、适配场景3个方向,近期南昌绳金塔片区新开的遇南三等直营火锅品牌&#xff0c…

2026/10/15 9:14:13 阅读更多 →
为什么选择SmolVLA?anikitakis/vla_so101_pick_n_place_full_expert在消费级硬件上的惊人表现

为什么选择SmolVLA?anikitakis/vla_so101_pick_n_place_full_expert在消费级硬件上的惊人表现

终极Rust模式匹配指南:解构复杂数据结构的7个实战技巧 【免费下载链接】rust 赋能每个人构建可靠且高效的软件。 项目地址: https://gitcode.com/GitHub_Trending/ru/rust Rust模式匹配是处理复杂数据结构的强大工具,它不仅能让代码更简洁&#x…

2026/10/15 6:22:50 阅读更多 →

最新新闻

量子计算对传统加密的威胁与防御策略

量子计算对传统加密的威胁与防御策略

1. 量子计算威胁全景图解析量子计算正在从实验室走向现实应用,这种新型计算范式对传统安全体系构成了前所未有的挑战。作为测试人员,我们需要从底层原理到实际影响建立完整的认知框架。量子计算机利用量子比特(qubit)的叠加态和纠…

2026/10/15 9:42:38 阅读更多 →
校园服务平台毕设拆解:Spring Boot+Vue+MySQL全栈实践

校园服务平台毕设拆解:Spring Boot+Vue+MySQL全栈实践

简介:这份毕业论文围绕校园服务平台的设计与实现,基于Java、Spring Boot与MySQL,完整覆盖从绪论、开发技术介绍、需求分析、可行性分析、功能分析、业务流程分析、数据库设计、详细设计到系统测试等全部章节。文档以单一DOC格式提供&#xff…

2026/10/15 9:42:38 阅读更多 →
SpringAI整合阿里百炼与火山引擎实战:智能客服性能优化

SpringAI整合阿里百炼与火山引擎实战:智能客服性能优化

1. 项目背景与核心价值最近在帮一家电商平台搭建智能客服系统时,我深度试用了SpringAI框架对接阿里百炼和火山引擎的方案。这个技术组合完美解决了我们面临的三个痛点:第一是传统NLP服务响应速度慢(平均800ms),第二是多…

2026/10/15 9:42:38 阅读更多 →
计算机视觉落地实战:从模型精度到工程化系统集成

计算机视觉落地实战:从模型精度到工程化系统集成

1. 从“刷榜”到“交活”:计算机视觉的评判标准变了过去几年,只要提到计算机视觉,大家的第一反应往往是“模型精度又涨了几个点”“某某数据集上又刷新了SOTA”。这套评价体系在学术圈没问题,但一旦进入真实项目,你会发…

2026/10/15 9:42:38 阅读更多 →
LeRobot模仿学习数据质量与版本化实践:从翻车案例到避坑指南

LeRobot模仿学习数据质量与版本化实践:从翻车案例到避坑指南

从LeRobot的一件小事说起:我去年用LeRobot跑一个自主抓取的模仿学习项目,一开始只有200条示教数据,模型成功率高得离谱,同事看了都以为我们放水。后来我想着“多存点总不会错”,又补了300条,把抓取角度、光…

2026/10/15 9:42:38 阅读更多 →
RetinaFace人脸检测与关键点定位工程实践指南

RetinaFace人脸检测与关键点定位工程实践指南

1. 为什么RetinaFace不是“又一个”人脸检测模型,而是工程落地的分水岭在某高校计算机视觉实验室带学生做毕业设计时,我连续三年遇到同一个问题:学生用YOLOv5或SSD跑通人脸检测后,一到实际场景就崩——遮挡、侧脸、低光照、小尺寸…

2026/10/15 9:41:37 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →