Linux进程状态详解:从R/S/D/T到僵尸与孤儿进程的排查指南

1. 一张进程列表引发的掉发:STAT列背后是调度器的底层判断

1.1 状态位不是给运维看的装饰,而是内核的调度依据

在Linux下跑ps -l或者ps aux,STAT那一列永远是几个大写英文字母加符号的组合。R、S、D、T、Z、X,第一次看到的人很容易以为是某种运行等级编码,或者干脆忽略掉。但搞懂这一列,其实等于搞懂了"内核眼中的进程状态机"。

我们平时说"这个进程还活着""那个进程挂了",这是人话。内核不能这么模糊,它需要一个精确的字段来标记每个task_struct当前处于什么阶段,而这个字段会直接参与调度器的决策。换句话讲,状态位是给内核看的"排班表",不是给人看的装饰品。比如说,一个进程如果状态位是R,调度器就会把它放进可运行队列,参与CPU时间片分配;如果是S,调度器就知道它在等某个外部事件,暂时不用给它CPU;如果是D,调度器知道它正在内核态做不可打断的IO等待,不能把它拉出来重新调度。

这跟我们在电梯间看到的"维修中""停止服务"是同一个道理。电梯可以正常运行、可以暂停、可以在维修,维修状态下你按任何楼层按钮它都不理你,因为它的内部状态不允许被打断。Linux进程的状态位,本质上就是内核给每个进程贴的一张运行状态标签,背后是一整套状态迁移逻辑。

1.2 先把STAT列常用字母和辅助标记认全

看进程状态最常用的三条路:

  • ps -l:输出里STATE列显示进程状态
  • ps aux:STAT列显示状态加辅助符号
  • cat /proc/<pid>/status:里面有State: R (running)这样更详细的行

内核源码task_state_array[]里其实有六种状态字母:R(TASK_RUNNING)、S(TASK_INTERRUPTIBLE)、D(TASK_UNINTERRUPTIBLE)、T(TASK_STOPPED或TASK_TRACED)、Z(EXIT_ZOMBIE)、X(EXIT_DEAD)。还有I(TASK_REPORT_IDLE),那是内核线程或者idle任务常用的空闲状态,很多ps版本里也能看到。

除了主字母,STAT列还经常出现附带符号,这里也顺带说清楚:

辅助符号含义常见场景
+位于前台进程组你在终端前台跑的命令
s会话首进程通常是shell本身
l多线程进程内有多线程
<高优先级用nice -n -20启动
N低优先级用nice调低过
L内存页被锁定实时进程锁页,较少见

新手不需要把辅助符号全背下来,但要能看出主字母。因为后面排查问题时,状态主字母才是决定操作方案的依据。看到D你慌,看到Z你也慌,但看到S和T你可以安心忙别的。

2. R 和 S:绝大多数进程的"日常状态",别再误判成死机

2.1 R状态是排队等待CPU,不是独占CPU

R状态对应内核的TASK_RUNNING。很多教程说R代表"正在运行",这个说法不算错,但不够准确。准确讲,R代表这个进程处于可运行队列中,只要调度器给它机会,它就能立刻上CPU执行。

单核CPU同一时刻只能真正执行一个进程,但可运行队列里可能排着好几个R状态的进程。跑一个死循环程序,top里CPU占用可能接近100%,你再打开ps看那个进程,状态大概率就是R。但反过来看,并不是所有R状态的进程此刻都在CPU上跑,它可能只是排在队列里等调度器叫号。

举个例子,写个多进程死循环程序,四个核的机器上起二十个子进程全在跑死循环,你用top按CPU排序会发现每个进程在抢CPU,但ps里看,这二十个进程可能都在R状态。因为它们的共同点是"随时可以被调度",而不是"每个进程都占着一个核在跑"。

排查时遇到R可以不用太紧张:只要系统整体负载可控,R多不多不是关键。但如果R状态的进程数量远超CPU核心数,同时负载值很高,说明CPU已经过载,线程都在排队等时间片,这时候才该去分析是不是业务代码写死了循环、或者服务并发配置不合理。

2.2 S状态是可中断睡眠,kill它是有喊醒再处理的机会

S状态对应TASK_INTERRUPTIBLE,官方翻译叫"可中断睡眠"。这个状态形容得非常准确:进程正在等待某个事件,这个事件通常不是CPU,而是IO完成、锁释放、定时器到期、网络数据到达等等。在等待期间它不需要CPU,调度器自然也不会分配CPU给它。

它跟D的关键区别,是可以被打断。S状态下的进程收到信号,比如kill -15,内核可以把进程从等待队列里唤醒,让它先去处理信号。处理完信号,进程可以继续原来的等待,也可以按信号逻辑退出。

这也是为什么sleep 100这个命令启动后,你去ps看它是S状态,而不是T或者R。sleep做的本来就是定时等待,在等待间隔内它是"睡着的",不过这个睡眠可以被kill打断。你用kill -15给sleep发信号,它大概率立刻退出。如果它处在D状态,kill -15发过去一点反应都不会有。

2.3 为什么top里R很少、S一大片

很多人在八核机器上跑了一堆服务,打开top发现R状态寥寥无几,S状态倒是占满屏幕,于是怀疑自己是不是哪里搞错了。其实这是完全正常的状态分布。

系统里大多数进程都在等待:等待网络请求、等待磁盘IO返回、等待锁、等待定时器。这些等待统统体现为S。只有真正进入调度队列准备使用CPU的进程才表现为R。所以看到一个四核机器负载5、但R状态的进程就三五个,别的全是S,这完全可能。负载数字衡量的是"可运行进程加不可中断睡眠进程的总和",不是说负载5就有5个进程在抢CPU。

理解了R和S,很多"系统是不是卡死了"的疑问能省掉一半。一个进程停在S状态,别急着说它死锁或者卡死,先看看它在等什么;一个进程是R,也别急着夸它在干活,它也可能是在无脑空转。

3. D 和 T:一个打不过也骂不醒,一个还能救回来

3.1 D状态与内核IO的关系:为什么kill -9都无效

D代表TASK_UNINTERRUPTIBLE,翻译是"不可中断睡眠"。这个名字在运维圈子里比较出名,因为碰到D状态进程,很多人会先试kill -9,然后发现完全没用,接着开始怀疑系统是不是中毒了。

其实D状态不是真正意义上的"死了",而是进程正在内核态等待某个必须同步完成的IO操作。典型的触发场景是磁盘IO、NFS网络文件系统同步读写、内存回收等。在这些场景下,内核让进程进入D状态,目的是保证IO操作的一致性。进程此刻可能持有内核某些资源,或者正在操作系统内部的数据结构,如果允许外部信号把它打断,内核里可能留下竞态条件甚至损坏数据。

所以内核干脆把进程"锁"在这个等待里:除非IO操作完成,或者内核明确决定把等待改造成可中断,否则外部信号一概不响应。kill -9本质也是发一个不可忽略的信号,但它同样没办法切入这个内核等待流程。

遇到大量D状态进程,正确的排查方向不是"杀进程",而是先查IO是不是出了问题。建议按这个顺序查:

  1. iostat -x 1,看看磁盘util是不是接近100%,await是不是飙升
  2. df -h和mount,确认挂载的网络文件系统是否还通着
  3. dmesg -T | tail,检查有没有IO错误、NFS超时、设备重置的记录

如果确实是NFS远端失联导致的D状况,光杀本地进程解决不了,得先恢复远端服务,或者把挂载恢复。要是单块磁盘故障导致的大量D,那要做的是备份数据、换盘,而不是在进程层面折腾。

3.2 T状态:Ctrl+Z、调试器断点与SIGCONT恢复

T状态是TASK_STOPPED,代表进程被暂停执行。这个状态比D温柔很多,它是"暂停但没有死"。

最经典的触发方式就是你在终端下跑一个长任务,不耐烦了按下Ctrl+Z。这时shell会给前台进程发送SIGTSTP信号,进程进入T状态。你再用jobs命令能看到它,用fg把它拉回前台继续跑,或者用bg放到后台继续跑,本质都是发送SIGCONT信号让它恢复执行。

另一个常见来源是调试器。用gdb调试程序的时候,一旦打了断点并命中,进程会进入T状态,准确说是TASK_TRACED。ps里一般也显示T,含义是"被调试器追踪,停在了断点处"。

T状态还常被用来做进程分析:你怀疑一个进程行为异常,可以先kill -STOP <pid>把它冻结,然后cat /proc/<pid>/stack之类去分析它此刻的调用链,分析完再kill -CONT <pid>恢复运行。不至于直接杀进程,影响面小很多。

3.3 一张表区分R、S、D、T的状态转移方向

用表格把四个主状态的方向理一遍,方便对照:

状态内核宏进程在干什么能被信号打断吗怎么恢复/退出
RTASK_RUNNING可运行,排队等CPU能执行完或用信号终止
STASK_INTERRUPTIBLE等待IO/定时事件能事件到达或信号唤醒
DTASK_UNINTERRUPTIBLE内核态同步等待IO不能等IO完成,或内核恢复
TTASK_STOPPED/TRACED暂停,保留现场能SIGCONT恢复或SIGKILL终止

初学阶段最容易混淆的是S和D:一个能被打断,一个不能。记住"S是浅睡眠,喊能醒;D是深睡眠,喊不醒"就行。

4. 僵尸进程:进程的遗体还躺在PCB里等父进程认领

4.1 一个进程的"身后事"到底怎么办

先说结论:僵尸进程不是"还活着的怪进程",而是已经退出、但退出信息还没被父进程读取的进程。

子进程调用exit()或者从main函数return之后,内核会把它接走,清理它打开的文件描述符、释放它占用的内存、关闭它的信号处理逻辑。但有一个东西不会立刻清掉,就是task_struct,也就是进程控制块。为什么保留它?因为父进程需要知道两个信息:子进程是正常退出还是被信号杀死的,退出码是多少。这些信息就存在这个PCB里,等待父进程调用wait或waitpid来领取。

如果父进程一直没有调用wait,子进程的运行实体早就没了,但PCB还在,这个状态就是Z,僵尸。用生活化的方式理解:一个人已经办完离职手续走人了,但流程要求主管签个字确认交接,主管一直不去签,档案就一直挂在系统里,工号占着不释放。

僵尸进程几乎不消耗CPU和内存,它真正消耗的只有一个task_struct空间,数量少的时候基本没感觉。但它的存在意味着父进程没尽到回收义务,长期积累几百几千个僵尸,才能感觉到进程表空间被占用的问题。

4.2 写个C程序复现僵尸进程,并验证kill -9无效

文本讲再多不如自己复现一次。写个最简单的C程序,目录里创建一个文件演示:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid = fork(); if (pid == 0) { printf("[child] pid=%d, 我现在退出\n", getpid()); exit(0); } printf("[parent] pid=%d, 子进程 pid=%d\n", getpid(), pid); sleep(60); printf("[parent] 终于睡醒了,开始回收\n"); wait(NULL); return 0; }

编译运行:

gcc -o zombie_demo zombie_demo.c ./zombie_demo

程序刚起来的60秒内,子进程已经exit(0)了,父进程还在sleep。此时打开另一个终端执行:

ps -eo pid,ppid,stat,comm | grep zombie_demo

会看到类似这样的输出:

12345 5678 S zombie_demo 12346 12345 Z zombie_demo

PID 12346是子进程,它的STAT列已经变成Z。此时你尝试:

sudo kill -9 12346

系统只会回一句kill: (12346) - No such process或者干脆静默失败。因为kill用的是进程PID,但僵尸进程已经没有可以被信号处理的可执行环境了。这不是权限问题,不是信号类型问题,是它已经死了,只是没有"注销户口"。

想看到这个"no such process"后的效果,可以等父进程60秒睡眠结束,wait(NULL)收回子进程退出码,那就看不到Z了。

4.3 收拾僵尸的三种可落地方案

对付僵尸,不能对着子进程使劲,得对着父进程或者代码逻辑使劲。

方案一:让父进程调用wait或waitpid。这是最正规的做法。代码里在fork之后、合适的位置等待子进程,获取退出状态。现实中开发者在编写守护进程或并发服务时,往往会在SIGCHLD信号处理函数里调用waitpid(-1, &status, WNOHANG)来批量回收。

方案二:直接忽略SIGCHLD信号。内核把SIGCHLD发给父进程,也是为了让父进程知道"你有个孩子退出了"。如果程序明确声明不关心子进程的退出状态,可以在初始化时写:

#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { // 显式忽略 SIGCHLD,子进程退出后由内核自动回收 signal(SIGCHLD, SIG_IGN); pid_t pid = fork(); if (pid == 0) { printf("[child] 我退出了\n"); exit(0); } sleep(5); return 0; }

设置SIG_IGN之后,内核会在子进程退出时直接释放它的PCB,不再保留成僵尸。这是很多高并发服务中常见的选择:反正不在乎退出码,进程也挺多,每个都wait会拖累性能,干脆让内核直接回收。

方案三:如果父进程已经是个坏掉的程序,根本不会处理信号也不会wait,那最直接的办法是结束父进程。父进程一死,僵尸子进程就会被init进程收养,也就是next进程(PID 1)。而init进程是祖传的"收尸大队",它会循环调用wait,把所有这些无人认领的僵尸进程逐一回收。所以某些场景下,你可以先找到僵尸进程的PPID,确认是哪个父进程没干活,把它干掉,僵尸就跟着消失了。

需要说明的是,方案三属于应急操作,生产环境最好还是让开发同事修代码。

5. 孤儿进程:父进程先跑路,init会来接盘

5.1 孤儿进程诞生后PPID为什么会变成1

僵尸是"子先死,父不收尸",孤儿正好相反:父进程先退出,子进程还在正常运行。

父进程挂了之后,子进程不能平白无故没有"长辈",内核会把它的PPID改成1,也就是让它挂到init进程名下。这个机制叫reparent,重新分配父进程。如果把进程比喻成小孩,父进程就是监护人,监护人突然没了,系统不会丢下小孩不管,而是立刻指派一个"集体监护机构"来接管。

这个接管好处很大:孤儿进程还能继续执行,因为它的父进程死了不等于它自己要退场。它原本持有的文件描述符、内存、打开的网络连接都不会因为父进程先走而立刻释放,只有继续跑的进程自己退出或不依赖父进程的那些资源,才会正常清理。

举例场景:你在Shell里用nohup ./myserver &启动一个后台服务,然后关掉终端。Shell退出后,服务进程的PPID会变成1。很多人以为关了终端服务就没了,其实只要服务本身没从Shell领到"终端退出时发SIGHUP"的逻辑,进程就继续活着,被init接管。这就是孤儿进程最常见的生产场景。

5.2 孤儿进程的自动回收机制与subreaper

init进程接管孤儿之后,不需要开发者操什么心。它内部会不断调用wait,所以孤儿最后退出时,由init负责回收,不会变成僵尸。

现代Linux上还有一个叫subreaper的机制,可以理解成"二级收尸队长":某个进程可以通过prctl(PR_SET_CHILD_SUBREAPER)把自己设置成子孙进程的reaper,这样它的子进程变成孤儿后,会被它接管而不是直接跳到init。容器场景里经常用到,因为容器里的1号进程往往想自己管理子进程生命周期。

大多数情况下,理解到"PPID变1,init自动回收"就够了。碰到孤儿的现实问题是:你本来想停掉一个后台任务,结果发现它爹已经死了,直接kill又舍不得,只好顺着进程线索一路找,最后发现它挂在PID 1下面运行。这时候不要慌,孤儿是可以正常杀掉的,因为它只是换了个父进程,主体还活着。

5.3 僵尸与孤儿对照表,面试题终于能串起来了

很多面试官喜欢一次问完僵尸进程和孤儿进程,因为这两个概念正好互补。整理成对照表,思路一下就清晰了:

对比项僵尸进程孤儿进程
产生顺序子进程先退出,父进程还在父进程先退出,子进程还在运行
状态Z,已经不再执行正常状态,继续执行
是否占用资源只剩PCB,不占用内存和CPU正常占用资源
谁能收尸父进程调用waitinit或subreaper自动接管并回收
能被kill吗不能,已无执行上下文能,和普通进程一样
危害程度多到一定数量会占满进程表几乎没有,除非它的父进程死因值得深究

理解到这个层面,再回头看标题里"从R/S/D/T到僵尸/孤儿"这条线,其实是一条完整的状态迁移链:R/S/D/T是一个进程活着时的不同状态,Z是退出瞬间等待父进程善后的状态,X是一闪而过的真正释放状态,而孤儿描述的是"父子关系断裂后的存活方式"。

6. 手把手观察五个状态:从命令到状态机的真实操作

6.1 制造R和S:忙循环 vs sleep

想要看着状态变化,动手跑几个命令最直观。

先制造R状态。在终端开一个死循环:

while :; do :; done

另开一个终端,找到它的进程号:

ps -eo pid,stat,comm | grep while

看到STAT是R,因为while :; do :; done这个bash子进程在空转,CPU每一刻都分给它执行。再数一下有多少个R状态的进程:

ps -eo stat | grep '^R'

四核机器上,跑一堆死循环,R的数量会持续在核心数附近徘徊,而不会无限膨胀,因为没抢到CPU时间片的死循环进程虽然状态是R,但依然需要排队。

再制造S状态,开一个sleep 100,然后查看:

sleep 100 & ps -eo pid,stat,comm | grep sleep

STAT显示S,或者S后面跟个符号。因为进程在定时器等待中,不消耗CPU。对比一下死循环进程和的sleep进程,能看到同样的生命周期里,等待和忙等的区别。

6.2 制造T:Ctrl+Z暂停与恢复

在终端跑一个耗时的循环,比如:

find / -name "*.conf"

按Ctrl+Z,然后查状态:

jobs -l

输出里括号内会显示已停止或者英文Stopped,进程号也在这里。再通过ps确认状态:

ps -o pid,stat,cmd -p <那个进程号>

STAT会显示T,因为SIGTSTP把进程暂停在终端作业状态。这时试着用fg把它带回前台:

fg

进程恢复执行。再查状态又变回R或S,视它此刻真正在忙还是在等IO而定。

如果想用命令方式制造T,可以:

kill -STOP <pid> ps -o pid,stat,cmd -p <pid> kill -CONT <pid>

这样T和恢复的流程完全掌握在自己手里,比Ctrl+Z更可控。

6.3 一个窗口里同时观察Z和孤儿进程的PPID变化

把前面两个C程序合并一下,一次观察两种状态:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h> int main() { pid_t pid_b = fork(); // 这个子进程会变成孤儿 if (pid_b == 0) { // 子进程B:打印父进程PID,睡3秒后看父进程PID变了没 printf("[childB] 现在我的ppid=%d\n", getppid()); sleep(3); printf("[childB] 睡醒了,我的ppid=%d\n", getppid()); return 0; } pid_t pid_a = fork(); // 这个子进程会变成僵尸 if (pid_a == 0) { printf("[childA] 我直接退出,变成僵尸\n"); _exit(0); } printf("[parent] 我马上退场\n"); return 0; }

编译运行后,父进程是程序主体,会退场。子进程B会从打印的PPID里看到变化:刚开始是父进程PID,3秒后变成1。子进程A因为父进程已经不存在了,会被init接管,由init负责回收,所以它不会长期停留成Z状态,会很快被扫走。

想观察僵尸,就用4.2节的代码,让父进程占用较长的时间不回收子进程。想观察孤儿,就用5.2节的代码。两者对照着跑一遍,进程状态从R/S/D/T到Z/X这条完整链路基本就串起来了。

7. 关于这些状态,排障时我总结的几点经验

7.1 系统满载时R和负载的关系

排查线上问题,经常看到load average飙到四五十,但top里R状态的进程并没有想象中那么多。这很正常,因为负载计算把不可中断睡眠也算了进去,D状态进程同样会被计入负载。Linux的loadaverage统计的是"处于R或D状态的进程数量平均数",不是"正在使用CPU的进程数"。

所以光看负载高低没办法判断CPU是不是瓶颈,得配合top里的us/sy比例、vmstat里的r和b两列一起看。r列高说明CPU排队严重,b列高说明有进程卡在IO等待上,这两个的判断方向完全不同。

7.2 大量D状态时先看IO还是先杀进程

一次生产故障,某业务系统的进程全部卡在D状态,同事第一反应是kill -9,结果进程纹丝不动,最后重启宿主机才恢复。事后排查发现是NFS挂载点失联,网络包一直在重传,内核IO等待无法完成。

我的建议是:看到D状态大批量出现,第一件事是dmesg扫一眼有没有设备重连、IO error日志,然后iostat -x 1看设备utilization和await。如果确实因为远端IO失联,先把远端恢复或者umount挂载点。进程层面越是急着杀,越容易把系统搞得半死不活,因为那些进程可能持有文件系统锁、正在刷脏页,杀掉它们留下更深的文件系统元数据问题。

7.3 大量Z状态时该检查什么

僵尸进程零星一两个不用大惊小怪,比如某次ssh会话退出后留下的残留,过一段时间会被自动收走。但如果ps -eo stat里Z数量持续增长且不掉,重点查父进程:

ps -eo pid,ppid,stat,cmd | grep Z

找到僵尸进程的PPID,再查那个父进程在跑什么、是不是有异常退出或者没处理SIGCHLD。很多情况下是父进程本身被冻结了,或者代码里没写wait调用。生产环境如果出现批量僵尸,通常意味着某个服务的子进程逻辑有bug,比如fork了但不回收、或者sighandler写得太粗糙。

另一个容易踩的坑是:很多人看到僵尸进程出现,第一反应是杀父进程让它变成孤儿让init回收。对单机进程这招确实奏效,但在容器里,容器内的1号进程不一定做了wait回收。容器环境里的僵尸可能需要你自己写个辅助进程去做reaping,或者配合subreaper机制处理。

这些状态看着是概念题,实际上每一条都能映射到真实的运维事故里。能把R/S/D/T和僵尸孤儿串成一条线,再去读ps输出的时候,心里会踏实很多——每个字母背后都对应着一个正在发生的系统故事。

相关新闻

RTX Spark与Scout AI:Windows原生AI代理终端架构解析

RTX Spark与Scout AI:Windows原生AI代理终端架构解析

1. 表面是硬件发布&#xff0c;实则是AI终端范式转移的临界点“微软英伟达发布Surface新旗舰&#xff01;RTX Spark加持&#xff0c;Scout AI登场”——这个标题在科技圈刷屏时&#xff0c;我正调试一套本地部署的多模态推理流水线。第一反应不是兴奋&#xff0c;而是警觉&…

2026/10/20 17:50:44 阅读更多 →
scrcpy可视化封装:基于Java 21 + Swing的安卓投屏管理工具

scrcpy可视化封装:基于Java 21 + Swing的安卓投屏管理工具

最近一直在折腾安卓投屏到电脑这件事。命令行工具 scrcpy 确实好用&#xff0c;但参数一多就头疼&#xff0c;特别是要在多台设备之间来回切换、调画质、看日志的时候&#xff0c;终端操作既不直观也容易打错。所以我自己写了个可视化封装工具&#xff0c;技术栈是 Java 21 Sw…

2026/10/20 17:49:42 阅读更多 →
双向NoC架构:时分复用与动态路由重构实战

双向NoC架构:时分复用与动态路由重构实战

简介&#xff1a;本资源为英文原版学术专著《Reconfigurable Networks-on-Chip》的中文译名版PDF&#xff0c;聚焦可重构片上网络&#xff08;NoC&#xff09;前沿研究&#xff0c;特别深入剖析双向NoC&#xff08;BiNoC&#xff09;架构的设计原理、动态通道重构机制与QoS保障…

2026/10/20 17:49:42 阅读更多 →

最新新闻

华为S2000B交换机命令配置大全:从Console口到VLAN划分实操手册

华为S2000B交换机命令配置大全:从Console口到VLAN划分实操手册

简介&#xff1a;这份资源是面向网络运维人员与华为交换机初学者的中文命令配置速查文档&#xff0c;针对设备调试中命令繁多、视图切换易混淆等痛点&#xff0c;系统梳理了常用配置指令与操作路径。包内共1个doc文件&#xff0c;约96KB&#xff0c;以文字条目形式集中呈现&…

2026/10/20 19:16:19 阅读更多 →
C#实时曲线图实战:LiveCharts选型、数据绑定与性能优化指南

C#实时曲线图实战:LiveCharts选型、数据绑定与性能优化指南

如果你最近在C#里做数据可视化&#xff0c;大概率会因为项目需要一个实时更新的曲线图而搜到LiveCharts。我第一次接触C# LiveCharts组件库&#xff0c;是给某设备监控系统做实时看板的时候——当时用自带Chart控件&#xff0c;数据点到两万以后&#xff0c;界面已经明显拖不动…

2026/10/20 19:16:19 阅读更多 →
ESP32-C3电容爆炸闹钟:高压升压与放电实战

ESP32-C3电容爆炸闹钟:高压升压与放电实战

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

2026/10/20 19:16:19 阅读更多 →
响应式架构底层逻辑解析:从依赖收集到手写迷你响应式系统

响应式架构底层逻辑解析:从依赖收集到手写迷你响应式系统

1. 从“rea”这个标题说起&#xff1a;一个被低估的通用缩写第一次看到“rea”这个标题的时候&#xff0c;我脑子里蹦出来的第一反应是——这大概率又是一个被缩写玩坏的项目名。在技术圈混久了你会发现&#xff0c;越是短到只有三个字母的标题&#xff0c;背后藏的东西往往越不…

2026/10/20 19:16:19 阅读更多 →
从rea项目拆解到落地:需求分析、架构设计与运维全链路实战

从rea项目拆解到落地:需求分析、架构设计与运维全链路实战

1. 从“rea”这个标题说起&#xff1a;一个极简命名背后的完整项目思维第一次看到“rea”这个标题&#xff0c;很多人会愣一下——三个字母&#xff0c;没有上下文&#xff0c;没有说明&#xff0c;甚至不知道它指代什么。但恰恰是这种极简命名&#xff0c;在真实的项目开发中非…

2026/10/20 19:16:19 阅读更多 →
ESP32本地工作台:为什么SDK越强,越需要确定性开发基座

ESP32本地工作台:为什么SDK越强,越需要确定性开发基座

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

2026/10/20 19:15:18 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50: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/20 9:50:45 阅读更多 →