news 2026/9/28 17:12:32

ps ax调度:从进程状态到内核调度器排查实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ps ax调度:从进程状态到内核调度器排查实战

线上环境一有点风吹草动,很多人第一反应就是敲ps ax。在运维和后端这个圈子里,ax 这两个字母已经变成肌肉记忆:不管是负载飙高、接口超时还是 CPU 打满,先刷一眼进程列表总不会错。最近圈里还有个热词叫 ax 调度,说的其实不是某种神秘的调度算法,而是大家最朴素的直觉——先 ps ax,再看调度状态。但多数人刷完 ax 只盯着 PID 和 COMMAND 两列,看到几个可疑进程就顺手 kill,这恰恰把 ax 最有价值的部分浪费掉了。真正值得读的是 STAT 列、TIME 列,以及它们背后那套内核调度器的工作逻辑。这篇就围绕 ax 调度这件事,把进程状态、负载计算、优先级、vruntime,再到一次典型 D 状态排查串起来,适合刚接触 Linux 排查的运维,也适合想补一补调度底层知识的后端开发。

1. 为什么 ax 会成为排查调度的第一条命令

1.1 ps ax 输出里藏着哪些调度信息

先把这个命令本身讲透。ps ax是 BSD 风格的进程列表命令,a负责列出所有带终端的进程,x负责列出所有不带终端的进程,两者合起来,就约等于整台机器上的全部进程。这也是它和ps -ef的最大区别:ps -ef同样能显示全部进程,但输出列更偏进程派生关系(PPID),而ps ax默认带着 STAT、TTY、TIME 这些跟调度强相关的列,一眼扫过去就能对系统“当时的状态”有个大致判断。

ps ax | head -20

拿一台正在压测的机器举例,输出会长这样:

PIDTTYSTATTIMECOMMAND
1?Ss0:00/sbin/init
2?S0:00[kthreadd]
25192pts/0R+0:08python app.py
25193?D0:00nginx: worker process

这里每一列都不是摆设。PID 和 COMMAND 不用多说,TTY 的?表示进程没有控制终端,通常是守护进程或内核线程;STAT 是进程当前调度状态;TIME 不是进程启动到现在经过的时间,而是它累计消耗的 CPU 时间,单位是分钟和秒。如果 TIME 长得很快,说明进程一直在抢 CPU;如果 TIME 几乎不动但进程活着,那它多半在睡眠或者等待状态里泡着。

ps ax默认不显示 CPU 占用排序,我实际排查时几乎总会加自定义输出:

ps ax -o pid,ppid,stat,%cpu,%mem,etime,cmd --sort=-%cpu | head -20

etime是进程已运行时长,%cpu是进程对单个逻辑核的占用百分比。这样一出来,最吃 CPU 的进程排最前面,状态、父进程、运行时长全在一屏里,高负载排查第一眼就能抓住重点。顺带说一句,ps aux也能看,它比ps ax多 USER、%CPU、%MEM 三列,日常够用;但ps ax配合-o自定义更灵活,想看什么列自己拼,这是我喜欢它的原因。

1.2 从 ax 到调度器:先看结果,再看原因

随手一刷的进程列表,其实是一张“调度快照”。Linux 里成千上万个进程不可能同时都在 CPU 上跑,CPU 核心就那么几个,谁上 CPU、谁排队、谁被换下来,都是调度器说了算。我们看到的每个进程状态、累计 CPU 时间,本质上都是调度器决策后的输出结果。这就是为什么光看 COMMAND 列没用:哪怕看到一个进程 CPU 占比很高,你也看不出它是真的在烧计算,还是因为优先级太高长期霸占 CPU,又或者卡在某个内核函数里出不来。

用一个生活化类比:CPU 相当于只有一个窗口的食堂,进程是排队窗口的队伍,调度器是窗口背后维持秩序的那套规则。ps ax只能告诉你“现在谁站在队伍哪个位置”,至于队伍为什么这么长、某个人为什么一直卡在窗口不动,它不会直接告诉你,得看状态和内核等待点。所以接下来要重点拆 STAT 列,它是整个 ax 调度体系里最值得练眼力的部分。

2. 读懂 STAT 列,等于拿到调度状态机的仪表盘

2.1 状态字符速查:一个字母一个含义

STAT 列看起来像一堆奇怪的字母组合,其实拆开看很简单。第一个字符是进程主状态,后面跟着的是修饰字符。主状态里最常见的是 R、S、D、Z、T、I、X 这几种,含义整理成一张表:

主状态字符含义通俗解释
Rrunning / runnable正在运行或排队等待 CPU
Sinterruptible sleep可中断睡眠,常等事件/信号
Duninterruptible sleep不可中断睡眠,通常卡在内核 IO 路径
Zzombie僵尸进程,进程已结束但父进程没回收
Tstopped被暂停,常因收到 SIGSTOP
Iidle kernel thread空闲内核线程,属于 D 状态的特殊成员
Xdead即将完全退出,正常瞬时状态

需要注意,R 状态并不是“正在运行”的专属标识,它表示进程当前在运行队列里处于可运行状态,可能真的在某个核上执行,也可能正在排队等核。S 状态则是进程因为等待某个事件(比如网络包、锁、定时器)主动让出 CPU,事件没来就一直睡,来一个信号就能醒。所以 ps ax 里出现大量 S 状态很正常,出现大量 R 状态通常说明 CPU 资源紧张,出现大量 D 状态则要立刻警觉。

修饰字符也很关键:s 表示该进程是会话首进程(通常带终端);l 表示多线程;+ 表示位于前台进程组;< 表示高优先级(nice 为负);N 表示低优先级(nice 为正)。比如常见的Ss是会话首进程正在睡眠,R+是前台进程正在运行,Sl是多线程进程正在睡眠。看到<或N时,顺带用ps -o nice,pri验证一下调度优先级,有时候一个任务长期霸占 CPU,就是因为它不知被谁调成了负 nice。

2.2 D 状态:卡在内核路径上的进程有多难缠

D 状态是 ax 调度排查里最经典的“坑”。D 全称 TASK_UNINTERRUPTIBLE,意思是进程进入了一个不能接收信号的内核等待路径,常见场景包括等待块设备 IO、NFS 网络文件系统响应、内存回收、内核锁等。此时你在用户态敲任何 kill 命令都没用,因为信号会排在那边,但由于进程无法从内核路径返回用户态,信号压根没机会被处理,表现就是 kill -9 打上去毫无反应。进程不是不响应,而是暂时无法响应。

很多次线上负载异常,都是 NFS 或存储阵列抖动引发的一连串 D 状态进程。排查时可以统计 D 状态进程数量:

ps ax -o stat= | awk '$1 ~ /^D/ {n++} END {print n}'

如果数量从 0 突然涨到几十,基本可以断定 IO 层面出问题了。接下来要定位具体是哪些进程,把 PID 和 COMMAND 打印出来:

ps ax -o pid,ppid,stat,cmd | awk '$3 ~ /^D/'

再看某个 D 状态进程在内核里到底等什么:

cat /proc/<PID>/wchan

这个文件会给出当前进程在内核栈中等待的函数名,比如nfs_wait_bit_killable、wait_on_page_bit、blkdev_direct_IO等。看到 NFS 相关函数,就去查挂载点和网络连通性;看到通用块设备等待,就查磁盘 IO 和存储。定位方向对了,问题就解决了一大半。

这里有个操作纪律必须强调:出现 D 状态进程,千万不要急着 kill -9。内核通常会在 IO 超时或底层恢复后让进程返回,你真正要修的是存储、网络、文件系统这类底层依赖。如果遇到极端情况(比如远端存储彻底失联),只能耐心等内核超时,或者评估重启机器的代价。比起瞎 kill 一顿,这些动作才是有意义的。

2.3 Z 状态:父进程没接住的僵尸进程

Z 状态通常不会让负载飙升,但它比 D 状态更让人头皮发麻。僵尸进程的出现机制其实很简单:子进程 exit 之后,内核不能立刻把它的 task_struct 删掉,必须留一个残骸等父进程调用 wait() 来回收;如果父进程一直不回收,子进程就永远以僵尸姿态挂在进程表里。

用 ps ax 判断僵尸进程的经典姿势:

ps ax -o pid,ppid,stat,cmd | grep -i defunct

输出里 COMMAND 列会出现<defunct>标记。僵尸进程没法直接 kill,因为进程本身已经死了,要处理的是父进程:先看 PPID,确认父进程是不是某个有问题的业务进程或脚本,再考虑重启父进程或父进程链,让 init 接管并回收。

海量僵尸进程还会带来一个隐蔽风险:内核虽然会保留僵尸进程占用的 task_struct,但 PID 空间会被快速耗光,新进程 fork 失败。我见过一台机器因为父进程的 bug,短短半天攒了 2800 多个僵尸进程,业务进程尝试 fork 时报cannot allocate memory,看着像内存问题,一查进程表才发现是 PID 耗尽了。所以 monitoring 里不能只看负载和内存,僵尸进程数量也是个值得接进告警的指标。

3. 从 ps ax 到内核调度:负载、nice 与 vruntime 的关系

3.1 load average 到底在算什么账

之前提到“ax 调度”,很多人会顺手敲uptime/top,看到 load average 三兄弟。这三个数字(1 分钟、5 分钟、15 分钟)经常被人误解成 CPU 使用率,实际上它们统计的是内核调度队列里处于活跃状态的任务数量:TASK_RUNNING(可运行)与 TASK_UNINTERRUPTIBLE(不可中断睡眠)的加权滑动平均值。换句话说,S 状态进程再多也不会进 load,D 状态进程反而是 load 的重要组成部分。

这解释了两种经典场景。场景一:一台单核机器跑着一个死循环,CPU 使用率顶到 100%,load average 在 1.0 附近晃,这其实是正常现象,因为负载统计的是队列里的任务数量,而不是 CPU 占用百分比。场景二:8 核机器 CPU 占用只有 30%,load average 却稳定在 8 上下,这种事一看就要警惕,大概率有 8 个左右进程进入不可中断睡眠,通通卡在 IO 等待上。后一种情况用 CPU 监控根本发现不了,得靠ps ax看 STAT 和vmstat 1 5的 b 列(处于不可中断睡眠的进程数)。

vmstat里 r 列表示正在运行/排队等待 CPU 的进程数,b 列表示不可中断睡眠进程数。r 长期接近 CPU 核数说明 CPU 压力大,b 常有值就值得去查 IO。这套组合拳比单看 CPU 使用率靠谱得多,也是我在第 4 章实战里会反复用到的思路。

3.2 nice 与 vruntime:CFS 的公平游戏规则

接下来聊最基础也是最重要的调度细节:nice 和 vruntime。Linux 默认的完全公平调度器(CFS)从内核 2.6.23 一路演进到现在,其核心设计目标是让每种任务都获得“相对公平”的 CPU 时间。这里的公平不是简单按进程数量平分,而是按权重来。nice 值从 -20 到 19,数字越小越“高贵”,优先级越高,默认是 0。

比如两个 CPU 密集型进程竞争一个核,一个 nice 0、一个 nice 10,内核会按权重比例分配。nice 每差 1,权重大约差 1.25 倍,nice 0 和 nice 10 的权重差距约 1.25^10 ≈ 9.3 倍,所以 nice 0 进程大约拿到 90% 的 CPU,nice 10 只有 10%。这就是renice的现实意义:

renice -n 10 -p 25192 # 把目标进程 nice 调高 10,让它少抢 CPU

进程能否被调度,不是按“谁跑得久谁先让”来排,而是维护一个虚拟运行时间 vruntime。进程实际运行越久,vruntime 涨得越多;权重越大的进程,vruntime 涨得越慢,所以它更容易排在队列前面。调度器每次选 vruntime 最小的先去跑,本质上是让所有进程的虚拟运行时间尽量对齐。这里顺带提一句:Linux 6.6 引入了 EEVDF 调度器,把 CFS 的红黑树改成了更精细的延迟分配算法,但虚拟运行时间的核心思想仍然是理解调度行为的地基。

实际排查中,看到某个后台任务长期抢占 CPU,可以用 nice 调低它的份额,而不是简单暴力 kill。它比 kill 温和,也更符合生产环境“保留业务能力”的原则。至于怎么确认当前进程的 nice 值,用ps -o pid,nice,cmd -p <PID>即可。

3.3 实时调度策略:需要超越 CFS 的场景

CFS 默认解决的是普通任务之间的公平问题,但有些场景需要“特殊任务优先”,比如实时音频处理、DPDK 网络收包线程,这些任务要求严格的低延迟和可预测性,不能跟批量计算任务一起排队。Linux 为此保留了实时调度器类 SCHED_FIFO 和 SCHED_RR,优先级范围 1 到 99,数字越大越优先。

查看当前进程的调度策略和优先级:

chrt -p 25192

把某个进程改成 FIFO 实时策略并设置优先级:

chrt -f -p 50 25192

这里必须给新手提个醒:不要在生产环境随手把普通进程调成实时策略。实时任务会无条件抢占所有 CFS 普通任务,如果你把一个纯空转的死循环进程设为 SCHED_FIFO 且优先级很高,它可能把一个核甚至整个系统“焊死”,连 SSH 都响应不了,到时候你手里 ps ax 再熟练,键盘按破也救不回来。我见过的实践经验是:确认业务确实需要硬实时能力,并且完整评估过调度风险之后,才在特定线程上启用实时策略。多数 Web/后端服务根本用不到这一步,看看chrt -p的输出,知道有这么回事就够了。

4. 实战复盘:一次 CPU 不高、负载爆表的 ax 调度排查

4.1 现场还原:先 ps ax 扫一眼全局

有一年夏天,我收到一台应用服务器的告警:load average 连续 15 分钟都在 8 以上,但 CPU 使用率只有 30% 左右。这种“CPU 不高负载高”的组合,经验告诉我多半不是计算问题,而是进程被“卡”住了。第一件事依旧是敲 ps ax,先看全局。

当时uptime显示 load average 是 8.7 / 8.2 / 7.9,vmstat 1 5的 b 列维持在 7~9,r 列却只有 0~1。说明有七八个进程因为某种原因进不了运行队列,在不可中断睡眠里挂着。随即执行:

ps ax -o stat= | awk '$1 ~ /^D/ {n++} END {print n}'

输出 8,和 load 基本对得上。到这里基本可以确定:这 8 个 D 状态进程就是负载的主要来源,而不是 CPU 跑满了。下一步是把 PID 们揪出来:

ps ax -o pid,ppid,stat,cmd | awk '$3 ~ /^D/'

当时输出集中在几个 nginx worker 和 PHP-FPM worker 上,COMMAND 统一指向一个挂载的 NFS 存储目录。这就把范围缩小到了一个很常见的点位:NFS 后端卡顿。

4.2 顺着 wchan 找到 D 状态进程的内核等待点

确认进程是哪些之后,为了不漏判,我打开了其中一个 PID 的内核等待点:

cat /proc/28513/wchan

输出是nfs_wait_bit_killable,另一个进程则是wait_on_page_bit,这就足够说明问题了:这些 worker 正在等待 NFS 页缓存回写或读取完成,网络文件系统响应慢,内核路径没返回,进程只能挂着。再配合mount看挂载参数和nfsstat看 RPC 统计,现场很快锁定了是 NFS 服务端所在存储集群发生了性能抖动。

这里有个操作纪律要再次强调:出现 D 状态进程,千万不要急着 kill -9。D 状态的信号处理路径被内核卡住,kill 发过去只会让进程继续挂着,还可能让你在恢复窗口内浪费大量时间。正确做法是恢复底层依赖:我们当时联系存储侧确认故障,NFS 服务端恢复后,这 8 个 worker 自动从 D 状态退回 S 状态,负载在 3 分钟内回到 1 以下,一条进程都没杀。如果你遇到的是无法立即恢复的情况(比如远端存储彻底失联),只能等内核 IO 超时或者慎重考虑重启机器,因为强制重启的代价通常比等待更大。

4.3 问题恢复与事后监控加固

D 状态进程数量不是一个常规监控指标,但它比 CPU 使用率更能反映系统“卡”在哪。这次故障之后,我在监控里加了一个针对 D 状态进程数的采集项,最简单的脚本思路是这样:

#!/bin/bash d_count=$(ps ax -o stat= | awk '$1 ~ /^D/ {n++} END {print n+0}') if [ "$d_count" -gt 20 ]; then echo "D state processes: $d_count" | mail -s "IO stuck alert" ops@example.com fi

实际生产环境建议直接把 d_count 上报到 Prometheus + Alertmanager 或你团队已有的监控体系,阈值可以按机器角色来定,普通容器节点我习惯设为 5,NFS/存储型节点可以给到 20。同时把vmstat的 b 列也纳入趋势图,和刚才的 D 状态数量互验。另外,对已知使用 NFS 的挂载点,我会特别确认hard/soft与超时参数是否符合业务容忍度。软挂载虽然能更快让进程从 IO 等待中返回,但可能会掩盖数据一致性问题,生产数据库类路径通常不敢用 soft,这些都是要在上线前就定好的策略,不能等故障来了才纠结。

5. ps ax 的边界:调度排查工具矩阵

5.1 从瞬间快照到连续采样

ps ax 最大的限制是它只给“当前瞬间”的状态快照,你看不到一分钟前发生了什么,也不会记住任何历史数据。排查负载问题时,我通常把它当成第一步,而不是唯一一步。与 ps ax 互补的连续采样工具是老牌的 vmstat、pidstat、sar。

以 pidstat 为例,它来自 sysstat 包,可以按进程维度看 CPU、内存、IO 和上下文切换:

pidstat -u 1 5 # 每 1 秒采一次 CPU,采 5 次 pidstat -d 1 5 # 看每进程 IO 读写 pidstat -w 1 5 # 看每进程上下文切换次数

ps ax 定位“哪些进程异常”,pidstat 定位“如何异常”。比如 ps ax 告诉你 PID 25192 占用 CPU 高,pidstat 能进一步告诉你它是在用户态烧计算(%usr),还是在内核态处理 IO(%sys),还能看它的主动/被动上下文切换频率。多一个维度,判断就准一分。

sar 系列则适合事后回溯:sar -q 1 5查看运行队列长度和负载,sar -w 1 5查看每秒上下文切换次数。在高负载故障发生后,如果之前有部署系统监控,你完全可以翻出历史曲线,还原出 D 状态进程是几点开始聚集的、当时 IO 设备发生了什么。ps ax 解决的是“此时此地”,sar 解决的是“彼时彼地”,两者配合才是一个完整的排查闭环。

5.2 调度延迟和上下文切换怎么量化

调度的最终用户感受是“任务有没有延迟”,而不仅仅是“CPU 跑没跑满”。上下文切换频繁可能意味着系统在多个进程/线程间反复“翻牌”,锁竞争会导致可运行但无法推进的线程增多,这些光看 ps ax 的 STAT 列很难量化。

对上下文切换,先看 vmstat 的 cs 列;如果某个进程切得特别多,用pidstat -w 1 5就能看到具体进程的 cswch/s(自愿切换)和 nvcswch/s(非自愿切换)。自愿切换多,通常说明进程在等锁/等 IO;非自愿切换多,通常说明时间片被抢占,或者 CPU 核数不足导致排队严重。

再往下,可以用 perf 的调度事件分析调度延迟和 CPU 迁移模式:

perf sched record perf sched latency

perf sched 记录一段时间内的进程调度事件,然后统计每个进程的调度等待时间、运行时间、迁移次数。它能解释“为什么我的机器 CPU 没满,但某个服务就是慢”这类问题。这一步通常需要 root 权限,而且生产环境里 perf 的使用要谨慎,建议先在预发环境复现。不过一旦用起来,你会发现自己对刚才 ps ax 里那些 STAT 组合的理解会深一个层次。

5.3 工具速查表:先选对命令再动手

把这次实战用到的工具和适用场景整理成一张速查表,方便以后直接抄作业。

症状首选命令定位思路
负载高、CPU 也高ps aux --sort=-%cpu找 CPU 占用 TOP 的进程,核对业务合理性
负载高、CPU 不高ps ax -o stat=配合 awk、vmstat 1检查 D 状态进程数量与 b 列,转入 IO/存储排查
某个服务频繁超时pidstat -w 1、vmstat 1看上下文切换与锁竞争,必要时用 perf 深挖
出现大量僵尸ps ax -o pid,ppid,stat,cmd配合 grep defunct根据 PPID 定位父进程,修复回收逻辑或重启链路
某进程占用 CPU 过高ps -o pid,nice,cmd -p <PID>、renice调整 nice 降低竞争,或确认是否业务预期

这张表的核心思想是先看状态,再动资源。ps ax 的边界就在于它只是一个开始:它能告诉你进程现在是什么状态,但它说不出这个状态是怎么形成的。要彻底搞明白一次 ax 调度异常,你需要把进程状态、负载计算、IO 等待、优先级这些概念连成一条线,再用连续采样工具去验证。这也是我把这些内容串起来写的原因。

最后说点我自己的习惯。排查这类问题多了之后,我已经把 ps ax 的默认输出改成了一个更顺手的别名,在 .bashrc 里挂着:

alias ax='ps ax -o pid,ppid,stat,%cpu,%mem,etime,cmd --sort=-%cpu'

这样每次敲 ax,出来的不是默认的简版输出,而是按 CPU 占用排好序、带状态、带运行时长的全量视图。第一眼就能抓住最异常的进程,再配合 STAT 列判断它是真的在跑还是卡住了。个人最大的体会是:高负载从来不是问题本身,它只是调度器写给外界的症状清单。先别急着 kill,先看懂 ax 那一行行状态背后的等待与竞争,往往才是解决问题最短的路径。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 17:11:54

Isaac Sim 4.5.0部署与闪退排查:CUDA环境配置全攻略

1. 项目概述1.1 为什么要写这篇Isaac Sim部署笔记搞机器人仿真的人应该都清楚&#xff0c;NVIDIA Isaac Sim在机器人开发领域的地位几乎等同于“标配工具”——从机械臂抓取、导航避障到多机器人协同&#xff0c;这套基于Omniverse的仿真平台能把物理引擎、高保真渲染和ROS2接口…

作者头像 李华
网站建设 2026/9/28 17:11:26

Substrate Runtime:可验证执行的链上信任内核

1. 项目概述&#xff1a;Substrate 不是“另一个区块链框架”&#xff0c;而是重构信任基础设施的底层范式你搜“substrate”时&#xff0c;大概率会撞上一堆 Kubernetes、OCI、gVisor、Agent 的热词——这绝非偶然。Substrate 的真实定位&#xff0c;远不止于“波卡生态的开发…

作者头像 李华
网站建设 2026/9/28 17:10:48

JavaBean与工具类的区别:数据载体与静态方法集合的设计边界

写Java写了不少年&#xff0c;越到后来越发现&#xff0c;很多代码烂不烂&#xff0c;其实在“类”的设计阶段就已经注定了。我见过太多新人一头扎进需求里&#xff0c;把数据、逻辑、静态方法全部塞进一个类里&#xff0c;结果这个类既是实体又是处理器&#xff0c;review的时…

作者头像 李华
网站建设 2026/9/28 17:09:54

PLC通信数据打包不用愁,MOVE_BLK_VARIANT指令实战详解

1. 为什么MOVE_BLK_VARIANT是通信场景的“搬砖神器”1.1 通信中数据搬移的痛点做PLC通信时间久了你会发现&#xff0c;真正让人头疼的往往不是通信本身&#xff0c;而是通信前后的数据整理。比如你要把一组工艺参数发给视觉系统&#xff0c;数据在PLC里是一个结构完整的DB块&am…

作者头像 李华
网站建设 2026/9/28 17:09:42

MATLAB实现BP神经网络火焰识别:从图像特征到GUI部署

简介&#xff1a;基于BP神经网络的火焰识别资源面向机器学习初学者、图像识别研究人员及MATLAB开发者&#xff0c;适用于火灾预警与安全监控中的图像分类场景。压缩包共845个文件&#xff0c;体积约467MB&#xff0c;包含813张jpg火焰样本图片、17个m功能脚本、4个mat数据文件、…

作者头像 李华
网站建设 2026/9/28 17:09:23

DeepSeek V4.1 推理缓存优化全攻略:从 KV Cache 原理到工程实践

1. 缓存优化这件事&#xff0c;到底在优化什么先说个现象。本地跑大模型的人越来越多&#xff0c;但同一个模型&#xff0c;在不同机器上的表现差距能拉到好几倍。有人用4090跑DeepSeek V4.1跑得飞起&#xff0c;有人用同样型号显卡却慢得怀疑人生&#xff0c;甚至时不时爆显存…

作者头像 李华