Linux进程等待:如何正确回收僵尸子进程(wait/waitpid详解)
运维或者 C/C 服务端开发的朋友应该都见过这种场景ps -ef一列下来进程状态是Z命令行括号里写着defunct。Z就是 zombie僵尸进程。为什么会有这么多僵尸因为子进程死了父进程没有及时“收尸”。在 Linux 里子进程退出后并不会立刻从系统里消失而是需要父进程调用wait、waitpid这类系统调用去读取子进程的退出状态最后让内核把残留的进程结构清理掉。这个动作就是进程等待也就是本文标题里说的“死亡的子进程是如何被父进程等待回收的”。这篇文章我会用多年写服务端程序的实际经验从僵尸进程的形成说起把wait和waitpid的区别、status状态解析、非阻塞轮询、信号驱动回收的坑全部抖出来配合可直接复用的 C 语言代码。适合正在学习 Linux 系统编程的开发者、准备面试的校招同学以及被线上僵尸进程困扰的运维和后台开发。1. 谁在等谁先搞懂进程等待背后的生命周期逻辑1.1 子进程退出后为什么会变成僵尸进程要理解等待回收先得看看 Linux 内核是怎么管理进程的。每次调用fork()内核都会给新进程分配一份task_struct这是进程在内核中的“户口”。里面保存着 PID、父进程 PID、运行状态、打开的文件描述符列表、CPU 时间统计、退出码这些信息。当子进程执行完exit()或者从main函数return内核并不会马上把task_struct销毁而是先把它改成ZOMBIE状态同时给父进程发送一个SIGCHLD信号。为什么要留一个残缺户口因为父进程有可能想知道子进程到底是怎么死的。比如子进程执行一个任务失败了父进程需要拿到退出码来判断下一步怎么做。如果内核一出exit就把所有信息销毁那父进程就没地方问去了。所以内核会保留最小信息集PID、退出状态、部分资源统计等等父进程来认领。这就是僵尸状态的由来。僵尸进程真正占用的资源很少但它占着 PID 表项。PID 在 Linux 中是稀缺资源一个系统默认pid_max通常是 32768现在很多发行版已经调大到了 4194304 甚至更大但如果不回收大量累积后 PID 会被耗尽新的进程就没法创建了。更麻烦的是僵尸进程会一直存在于进程表中工具链、监控脚本每次遍历进程都会看到它造成混乱。1.2 父进程“失联”时孤儿进程和 init 的接盘机制如果父进程先于子进程退出子进程就成了孤儿。这时候内核会为它寻找一个新的“监护人”一般情况下是 PID 为 1 的进程。老派 Linux 里叫init现代发行版通常是systemd。systemd作为所有孤儿进程的收养者会周期性地调用wait来回收这些无人照看的子进程。所以单个短命程序里即使父进程死了子进程的僵尸状态也不会一直持续内核和systemd会自动兜底。但持久化服务父进程完全不同比如一个守护进程起着 N 个子进程处理请求父进程自己长期活着那子进程退出的回收责任就全压在父进程身上。父进程必须显式地调用wait系列接口否则僵尸进程就会一直累积。这也是为什么僵尸问题最常出现在长期运行的服务程序里。理解这一点就明白了进程等待的本质这不是一个可做可不做的“清理动作”而是父进程必须要履行的责任也是内核为了补偿“父进程需要知道子进程死因”而设计的交接流程。2. 选择 wait 还是 waitpid两个系统调用的底层差异2.1 wait() 的阻塞语义与基础用法wait是最简单的回收接口原型是#include sys/wait.h pid_t wait(int *status);wait做的事情是等待任意一个子进程退出。如果当前任意子进程都还活着调用wait的父进程会进入睡眠状态直到有子进程退出。返回值为退出子进程的 PID错误时返回 -1并设置errno。常见错误码包括ECHILD没有子进程可等待和EINTR等待过程被信号打断。status参数是个出参内核会把退出信息编码到status指向的整型变量里。用一句话概括编码逻辑正常exit(code)时退出码被放在第 8 到 15 位如果是被信号杀死的低 7 位放信号编号第 7 位还可能有核心转储标志。直接对着整型做位运算非常容易出错所以正式代码一律使用宏这部分放在 2.3 节详细讲。wait的最大局限性是“不挑食”它总是等待“任意一个”子进程不能指定等哪一个并且它是阻塞式的只要子进程不退出父进程就一直挂起。对于只需要处理单个子进程的脚本类程序wait足够。但服务端程序通常需要精细控制这就引出了waitpid。2.2 waitpid() 的精密控制pid 和 options 组合拳waitpid的原型比wait复杂不少#include sys/wait.h pid_t waitpid(pid_t pid, int *status, int options);第一个参数pid决定了“等谁”有很多取值规则pid 0等待指定 PID 的那个子进程。pid -1等待任意一个子进程和wait等价。pid 0等待与调用者处于同一进程组的任意子进程。pid -1等待进程组 ID 正好等于|pid|的任意子进程。最后两条常用于需要把同组进程统一管理的场景比如简单 shell 实现作业控制。日常开发最常用的还是pid 0和pid -1。options参数则可以改变行为0阻塞等待直到目标子进程退出。WNOHANG非阻塞。如果子进程还没有退出立即返回 0不挂起调用者。WUNTRACED子进程被信号停止如SIGSTOP时也返回而不只是退出时才返回。WCONTINUED子进程在停止后又被SIGCONT恢复时也返回。这些选项可以用按位或组合比如waitpid(pid, status, WNOHANG | WUNTRACED)就表示“非阻塞等待指定的子进程如果它暂停了也立刻告诉我”。waitpid返回值有三种情况大于 0 表示回收成功返回 PID等于 0 表示设置了WNOHANG且当前没有可回收子进程等于 -1 表示出错。2.3 状态宏的正确打开方式别再手动位移了status这位仁兄的位布局在不同 Unix 系系统上并不完全一致Linux 上也不是所有位都有明确含义。与其去记哪几位是退出码、哪几位是信号号不如老老实实用标准宏。我在面试里经常看到有人背“退出码在低 8 位”其实这是不准确的说法很容易误导。可靠的做法是下面这一组判断宏宏作用配合使用的宏WIFEXITED(status)是否正常退出调用 exit 或从 main 返回WEXITSTATUS(status)获取退出码WIFSIGNALED(status)是否被信号杀死WTERMSIG(status)获取信号编号WCOREDUMP(status)是否产生了 core dump 文件与WTERMSIG配合WIFSTOPPED(status)子进程是否处于停止状态WSTOPSIG(status)获取停止信号WIFCONTINUED(status)子进程是否从停止中恢复运行-举个例子当子进程被SIGSEGV段错误杀死时WIFSIGNALED(status)为真WTERMSIG(status)返回 11。如果子进程是自己调用exit(3)退出WIFEXITED(status)为真WEXITSTATUS(status)返回 3。这些宏其实是把位运算封装好了内部逻辑对应用层隐藏既不容易错可读性也强。实战中千万不要自己写(status 0xff)这种代码遇到WCOREDUMP这种非标准位就很容易踩坑。3. 从零实现父进程回收子进程完整代码与逐行解析3.1 单子进程阻塞回收最朴素的 wait 用法先写一个最基础的例子父进程fork一个子进程子进程睡 2 秒后以退出码 42 退出父进程用wait回收并打印退出状态。#include stdio.h #include stdlib.h #include sys/wait.h #include unistd.h int main(void) { pid_t pid fork(); if (pid 0) { perror(fork); return 1; } if (pid 0) { // 子进程代码 printf(child [%d] is running\n, getpid()); sleep(2); printf(child [%d] exits with code 42\n, getpid()); exit(42); } // 父进程代码阻塞等待任意子进程 int status 0; pid_t waited wait(status); if (waited 0) { perror(wait); return 1; } printf(parent reaped child [%d]\n, waited); if (WIFEXITED(status)) { printf(child exited with code %d\n, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf(child killed by signal %d\n, WTERMSIG(status)); } return 0; }这段代码逻辑不复杂但有几处值得注意。fork之后必须判断返回值pid 0是子进程执行路径pid 0是父进程执行路径这里父子进程共享同一份代码靠返回值分流。子进程里的exit(42)真正执行时内核会向父进程发送SIGCHLD父进程因为已经阻塞在wait上会立刻被唤醒然后回收。为什么不建议在这里用return 42在main函数里return和调用exit效果几乎一样都会触发进程退出并返回状态码但子进程分支里的return 42只是从main返回同样会调用exit(42)。区别在于如果子进程分支在一个被调用的函数里return不会触发整个进程退出容易造成流程混乱。建议在子进程分支中显式使用exit。这个例子还有一个隐藏技巧父进程在wait前没有对子进程做任何操作子进程也不共享父进程的文件描述符表快照之外的资源所以不需要额外清理。如果子进程之前打开过自己的文件进程退出时内核会统一回收无需担心。3.2 多子进程非阻塞轮询waitpid WNOHANG 的正确姿势真实的服务进程往往不止一个子进程而且子进程的存活时间各不相同。这时如果都用阻塞wait每次停止在某个子进程上整体流程会被拖住。更好的做法是用WNOHANG非阻塞轮询。下面这个例子一次创建 5 个子进程每个子进程睡 1 到 5 秒随机退出。父进程在主循环里不断调用waitpid(-1, status, WNOHANG)把所有已经退出的子进程逐个回收同时统计还活着的子进程数量。#include stdio.h #include stdlib.h #include sys/wait.h #include unistd.h #include time.h #define CHILD_NUM 5 int main(void) { pid_t pids[CHILD_NUM] {0}; for (int i 0; i CHILD_NUM; i) { pid_t pid fork(); if (pid 0) { perror(fork); exit(1); } if (pid 0) { srand(getpid()); int sec rand() % 5 1; printf(child [%d] will sleep %d sec\n, getpid(), sec); sleep(sec); exit(0); } pids[i] pid; } int alive CHILD_NUM; while (alive 0) { int status 0; pid_t waited waitpid(-1, status, WNOHANG); if (waited 0) { printf(reaped child [%d]\n, waited); alive--; } else if (waited 0) { // 没有退出的子进程睡一下再轮询避免忙等 usleep(100 * 1000); } else { if (errno ECHILD) { printf(no more children\n); break; } perror(waitpid); break; } } printf(all children reaped\n); return 0; }关键点在于alive变量。waitpid每次成功回收一个子进程alive就减 1直到为 0循环结束。如果waitpid返回 0说明还没有子进程退出此时不能死循环空转需要usleep睡眠一小段再继续。这就是“非阻塞”的意义父进程没被内核挂住可以在等待间隙干别的事比如处理网络事件。返回值 -1 且errno是ECHILD时代表所有子进程都已被回收再没有任何子进程可等待循环直接退出。还有一个细节rand()在子进程里用getpid()作为种子避免所有子进程生成同样的随机值。因为fork之后子进程会继承父进程的随机数种子如果不重新播种多个子进程可能睡相同秒数影响观察效果。3.3 捕获进程暂停与恢复WUNTRACED 和 WCONTINUED 的实际应用有些场景下父进程不仅关心子进程“退出”还关心子进程“被停止”。最典型的是 shell 的作业控制用户按CtrlZ挂起一个后台任务shell 需要用waitpid的WUNTRACED捕获到“子进程停止了”这个事件然后在任务列表里标记状态。下面的代码演示了子进程收到SIGSTOP后父进程用WUNTRACED感知停止事件再主动给子进程发SIGCONT让它恢复运行最后等它退出。#include stdio.h #include stdlib.h #include signal.h #include sys/wait.h #include unistd.h int main(void) { pid_t pid fork(); if (pid 0) { perror(fork); return 1; } if (pid 0) { printf(child [%d] running\n, getpid()); while (1) { pause(); } exit(0); } int status 0; // 父进程进入阻塞等待但要求: 子进程停止时也要返回 pid_t waited waitpid(pid, status, WUNTRACED); if (waited 0) { perror(waitpid); return 1; } if (WIFSTOPPED(status)) { printf(child [%d] stopped by signal %d\n, waited, WSTOPSIG(status)); // 让子进程继续跑 kill(waited, SIGCONT); } // 这里再次等待子进程最终可能被杀或退出 waited waitpid(pid, status, 0); if (WIFEXITED(status)) { printf(child [%d] finally exited with %d\n, waited, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf(child [%d] killed by signal %d\n, waited, WTERMSIG(status)); } return 0; }子进程的while(1) pause()会让它一直挂着等待信号所以第一次waitpid阻塞后不会立即返回除非有人在另一个终端给子进程发SIGSTOP。为了测试方便你可以在子进程里主动raise(SIGSTOP)或让父进程隔几秒发SIGSTOP。真实 shell 场景下SIGSTOP往往由终端驱动产生这里的代码只是演示捕获能力。WIFSTOPPED(status)为真时WSTOPSIG(status)返回导致停止的信号编号大多数情况是SIGSTOP19或SIGTSTP20。注意到第一次waitpid使用了WUNTRACED如果不加这个选项即使子进程停止waitpid也不会返回父进程永远卡住。加了之后停止也算“事件”父进程可以响应。3.4 关于 SIGCHLD 异步回收的常见误区和更优写法信号驱动回收是进阶做法父进程不显式调用wait而是注册一个SIGCHLD信号处理函数在子进程退出时自动回收。很多同学会写成这样void sigchld_handler(int sig) { int status; pid_t pid waitpid(-1, status, WNOHANG); if (pid 0) { printf(reaped %d\n, pid); } }看起来没毛病但多子进程同时退出时会漏收。因为标准信号是不可排队的如果连续有 3 个子进程退出内核可能只投递一个SIGCHLD到父进程。信号处理函数跑一次waitpid只收一个子进程另外两个就留在僵尸状态了。我在早期做网关服务时就因为这个写法线上僵尸进程越积越多当时还以为是框架回收逻辑有 bug。正确做法是在 handler 里循环调用把当前所有已退出的子进程全部收干净void sigchld_handler(int sig) { int status; pid_t pid; while ((pid waitpid(-1, status, WNOHANG)) 0) { // 记录日志注意不能在 signal handler 里用 printf write(1, reaped\n, 7); } }注意信号处理函数里不要调用printf这类非异步信号安全函数简单场景用write写日志复杂场景把 PID 放入队列回到主循环再处理。注册信号时推荐用sigaction而不是signal因为signal在不同平台语义有差异sigaction更可控。如果不是对退出状态特别敏感也可以在子进程创建时直接signal(SIGCHLD, SIG_IGN)内核会自动清理子进程、不产生僵尸但代价是永远拿不到退出状态。对于监控型服务状态往往比“不产生僵尸”更重要所以更推荐循环回收写法。4. 实战排障僵尸进程缠上你时这样查这样解4.1 现场排查ps、top、/proc 目录三板斧遇到僵尸进程第一件事是确认“谁在死、谁该收”。最直观的是ps命令ps -eo pid,ppid,stat,comm | grep -w Z输出里STAT列显示Z的进程就是僵尸PPID列就是它的父进程。有些系统上还会在COMMAND列显示defunct一眼就能认出来。top命令第一行会显示zombie的数量如果持续增长基本上可以断定有父进程不回收。还可以进/proc验证cat /proc/pid/stat | awk {print $3}第 3 个字段如果是Z就是僵尸。/proc的信息更底层适合在脚本里自动化检查。找到僵尸进程的父进程后先去代码里排查这个父进程 fork 子进程后是否有路径缺失了wait或waitpid是不是子进程分支某种异常退出方式让父进程的等待代码没覆盖到常见的原因有三个父进程用signal(SIGCHLD, SIG_IGN)却又想拿到状态信号 handler 只wait了一次以及父进程在某个分支里提前return了根本没执行到最后的回收逻辑。4.2 读懂 errnowaitpid 返回 -1 时的三种经典情况waitpid返回 -1 时必须看errno这是个高频考点ECHILD调用者没有子进程可等待。常见场景子进程已经被回收过了又调用了一次waitpid或者在 fork 失败后调用 wait。需要修正逻辑重新梳理“每个子进程只回收一次”的原则。EINTR等待过程中被一个未屏蔽的信号打断。这不是致命错误正确的应对是主动重试常用写法是do { ret waitpid(pid, status, 0); } while (ret 0 errno EINTR);EINVAL参数不合法比如options传了一个不存在的标志位或者status指针非法。检查调用代码即可。面试里最理想的回答是说出ECHILD和EINTR的区别前者是“没有这个孩子”后者是“等到一半被叫走了”。实际开发中EINTR被很多人忽略导致回收逻辑在信号频繁的环境下失效。4.3 多子进程同时退出时 SIGCHLD 信号为什么会“丢消息”前面提到过信号是不可排队的这里展开讲一下原理传统 Unix 信号机制中对于同一个未决信号内核只会设置一个 pending 标志位不会记录发了多少次。如果你的父进程注册了SIGCHLDhandler而 5 个子进程同一时间退出可能只触发一次 handler。如果 handler 里只调用一次waitpid另外 4 个子进程依然停留在僵尸状态。所以所有老手都会强调在 SIGCHLD handler 里一定要用while循环回收并且要带WNOHANG否则有可能 handler 执行时恰好没有子进程退出阻塞等待就麻烦了。这段经验放在任何一本 Linux 系统编程书籍的实战部分都能看到但没踩过坑的人很难理解为什么。另外如果子进程是自己调exit退出而不是被信号杀死SIGCHLD投递是可靠的。但不可排队造成的“少调用 handler”问题依然存在。稳妥起见采用循环回收是唯一方案。4.4 日常开发中的几个机制习惯我分享几个自己长期坚持的机制算不上高深但很管用第一fork 之后立刻用一个数组或者列表登记子进程 PID。这样后续想定向waitpid(pid)时一目了然也方便做超时控制。如果只靠waitpid(-1, ...)通配多个子进程混在一起时不好判断是哪个业务模块退出了。第二解析status永远用WIFEXITED那组宏。不要自己写位运算。哪怕我背得过status编码规则也不写因为宏的可读性和可移植性都比手算强太多。第三明确阻塞与非阻塞的使用边界。简单的单任务脚本用wait就够了不要引入复杂的信号处理网络服务的主循环里用非阻塞轮询把回收逻辑作为事件处理的一部分。别为了“好看”把回收放到信号异步流程里结果把自己坑了。第四注意线程和进程的回收差异。线程退出不是用wait回收而是pthread_join或分离线程。二者很容易混淆尤其是在用pthread的进程里又 fork 了子进程时别把线程回收忘了。第五生产环境排查时多使用strace -p pid观察父进程是否在调用wait4内核里的实际系统调用是wait4。如果不调用那说明代码里压根没走到回收流程如果调用了但返回值不对多半是参数或信号处理问题。strace输出最真实不用靠猜。这招我救过很多次场。最后再分享一个真实经历我曾经负责一个接入网关子进程负责处理长连接连接断开时子进程退出。有一阵子线上僵尸进程数量以每小时几十个的速度上涨排查时发现SIGCHLDhandler 里确实只调用了一次waitpid以为一次就能收一个结果高频退出场景下大量子进程堆积。把 handler 改成while循环之后僵尸进程数量直接归零。类似的坑你现在没踩过以后大概率也会遇到。希望这篇文章能帮你少踩几个。

相关新闻

Kubernetes 1.13.3 电商微服务离线部署与 TLS 证书链实战

Kubernetes 1.13.3 电商微服务离线部署与 TLS 证书链实战

简介:本资源是一套面向运维工程师与云原生初学者的Kubernetes实战教学包,聚焦电商微服务在k8s 1.13.3版本上的完整部署落地,解决企业级容器编排环境中服务治理、镜像管理、Ingress流量控制等典型问题。压缩包共6个文件,含3个.gz/t…

2026/10/9 6:07:02 阅读更多 →
Visual C++ 手搓本地搜索引擎:倒排索引、分词与 TF-IDF 排序实战

Visual C++ 手搓本地搜索引擎:倒排索引、分词与 TF-IDF 排序实战

简介:这份资源是面向C初学者与游戏AI爱好者的Surakarta人机博弈项目源码包,基于Visual C开发,核心围绕alpha-beta搜索算法与简单估值函数展开,适合想理解博弈搜索、搜索引擎式状态空间遍历及面向对象编程的读者练手。压缩包共8个文…

2026/10/9 6:06:02 阅读更多 →
TCP网络通信编程大作业:从三次握手到C语言Socket实战

TCP网络通信编程大作业:从三次握手到C语言Socket实战

简介:一份完整的TCP/IP课程设计大作业报告,基于C语言实现TCP网络通信编程,面向计算机网络或TCP/IP协议课程的学生与开发者。报告围绕客户/服务器通信程序展开,实现了注册、登陆、单聊、私聊、在线人数列表、退出等功能&#xff0c…

2026/10/9 6:06:01 阅读更多 →

最新新闻

生产级Coding Agent调优实战:Harness工程化决定落地下限

生产级Coding Agent调优实战:Harness工程化决定落地下限

1. 从"能跑"到"好用":生产级 Coding Agent 的最后一公里到底卡在哪Vibe Coding 这个词这两年被聊得很多,大意是开发者用自然语言描述意图,让 Coding Agent 去生成、修改、验证代码,人只负责把握方向和验收。听…

2026/10/9 6:35:27 阅读更多 →
Java Swing人事管理系统:JDBC+MySQL课程设计实战与避坑指南

Java Swing人事管理系统:JDBC+MySQL课程设计实战与避坑指南

简介:这份资源是一套基于 Java Swing、JDBC 与 MySQL 实现的人事管理系统课程设计项目,面向正在完成数据库课程设计、需要可运行参考案例的计算机相关专业学生。项目包含可视化软件界面,覆盖人员信息维护、数据库连接与增删改查等典型业务场景…

2026/10/9 6:35:27 阅读更多 →
MySQL校对规则:utf8mb4_general_ci与utf8mb4_bin的差异及选型

MySQL校对规则:utf8mb4_general_ci与utf8mb4_bin的差异及选型

1. 这两个校对规则到底在吵什么看你一脸问号地点进来,我猜你多半是遇到过这种情况:建表的时候复制了一段别人的SQL,里面有CHARSETutf8mb4 COLLATEutf8mb4_general_ci,或者是utf8mb4_bin,当时也没多想,能用就…

2026/10/9 6:35:27 阅读更多 →
PS5底层开发合规边界与技术可行性分析

PS5底层开发合规边界与技术可行性分析

我无法根据当前输入生成符合要求的博文。原因如下:项目标题 "AnyPS5" 缺乏明确指向性:该词在公开技术语境中无公认定义,既非官方产品名(索尼未发布/命名过 AnyPS5)、非开源项目(GitHub、GitLab、…

2026/10/9 6:35:27 阅读更多 →
claude-mem:为Claude Code打造跨会话长期记忆的实战指南

claude-mem:为Claude Code打造跨会话长期记忆的实战指南

用过 Claude Code 写真实项目的人,基本都遇到过这个场景:昨天刚跟 AI 讨论清楚的一个架构方案,今天新开一个会话,它完全不记得了。你在同一个仓库里翻历史对话记录,发现上一个会话已经把项目的来龙去脉都喂给了它&…

2026/10/9 6:35:27 阅读更多 →
Agent-Reach:LLM API智能路由与成本可控调度中枢

Agent-Reach:LLM API智能路由与成本可控调度中枢

1. 项目概述:Agent-Reach 是什么?它解决的不是“能不能用”,而是“怎么用得稳、用得准、用得省”Agent-Reach 这个名字乍看像某个开源模型或工具库,但结合 CLI、API、YouTube、Reddit 这些高频热词,再叠加上“zcode cl…

2026/10/9 6:34:27 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 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/8 21:13:17 阅读更多 →
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/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练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/9 6:17:20 阅读更多 →