renice 命令详解与参数实测(Ubuntu 22.04)

逐项实测 Ubuntu 22.04 的 renice(util-linux 2.37.2):-n/-p 调整运行中进程、root 调负值与权限边界、普通用户只能调高不能调低、-u 按用户、-g 按进程组(含部分生效现象)、老式写法与多 PID 批量、四类报错 rc=1、降权后调回受限,并与 nice 分工对照,附失控进程降载等实战场景。

Linux命令Linux系统UbuntuUbuntu 22.04命令行进程管理2026/10/15

renice 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 renice 的每一个常用参数与行为——-n 指定新 nice 值、-p 按进程 ID、-u 按用户、-g 按进程组、老式写法与多 PID 批量、普通用户"只能调高不能调低"的权限规则、root 调负值的能力边界、四类报错与返回码,全部命令与回显已在 Ubuntu 22.04(renice from util-linux 2.37.2)实测通过。

一、环境信息

本篇所有命令与回显均在以下环境实测采集,读者在同等环境(Ubuntu 22.04 服务器、util-linux 2.37.2)执行应得到一致结果。

  • 操作系统:Ubuntu 22.04.5 LTS(PRETTY_NAME="Ubuntu 22.04.5 LTS")
  • 架构:x86_64
  • renice 版本:util-linux 2.37.2(renice from util-linux 2.37.2)
  • renice 路径:/usr/bin/renice
  • 执行身份:root(普通用户限制的对照实验另建了演示用户 reniceu1)
  • 辅助验证工具:ps(procps)、su

💡 技术拓展:renice 与 nice 是"同族不同包"的一对工具——nice 是 GNU coreutils 8.32(/usr/bin/nice),renice 是 util-linux 2.37.2(/usr/bin/renice),两者底层都走 setpriority(2) 系统调用。分工一句话:启动时预设用 nice,运行中改判用 renice——

维度nicerenice
作用对象只能是它新启动的命令已在运行的进程/用户/进程组
典型时机启动时预设(跑批、备份)运行中干预(降载、提权)
按用户/进程组批量不支持支持(-u / -g)
调低(更负)能力同受 CAP_SYS_NICE/RLIMIT_NICE 约束同受约束
归属包GNU coreutils 8.32util-linux 2.37.2

二、命令概览

2.1 语法与测试数据

renice 的作用是:修改已在运行进程的调度优先级(nice 值)。它有三种等价的目标维度(来自 --help 的 Usage 块):

renice [-n] <priority> [-p|--pid] <pid>...    # 按进程 ID(默认)
renice [-n] <priority>  -g|--pgrp <pgid>...   # 按进程组 ID
renice [-n] <priority>  -u|--user <user>...   # 按用户名或用户 ID

测试数据:一组 sleep 1000 后台进程当"演示负载",用 ps -o ni 读取 NI 列验证每次调整;普通用户实验使用专用演示用户 reniceu1。全程只操作独立演示进程,不改动系统已有进程。

2.2 --help 全量输出(逐行照抄)

util-linux 风格的 help(注意输出以一个空行开头,-n 的选项名是 --priority 而非 nice 的 --adjustment):

$ renice --help; echo rc=$?

Usage:
 renice [-n] <priority> [-p|--pid] <pid>...
 renice [-n] <priority>  -g|--pgrp <pgid>...
 renice [-n] <priority>  -u|--user <user>...

Alter the priority of running processes.

Options:
 -n, --priority <num>   specify the nice value
 -p, --pid              interpret arguments as process ID (default)
 -g, --pgrp             interpret arguments as process group ID
 -u, --user             interpret arguments as username or user ID

 -h, --help             display this help
 -V, --version          display version

For more details see renice(1).
rc=0

逐项解读:

选项含义实测章节
-n, --priority <num>目标 nice 值(可省略,省略时直接跟数字,见 3.6 老式写法)3.1
-p, --pid后面的参数按进程 ID 解释(默认维度)3.1
-g, --pgrp按进程组 ID 解释,影响该组全部成员3.5
-u, --user按用户名/UID 解释,影响该用户全部进程3.4

2.3 版本信息

$ which renice
/usr/bin/renice

$ type renice
renice is /usr/bin/renice

$ renice --version | head -2
renice from util-linux 2.37.2

type renice 实测返回 /usr/bin/renice——renice 不是 bash 内置命令。版本行只有一个短句(util-linux 风格,区别于 coreutils 工具的两行版权输出),归属包为 util-linux 2.37.2。

三、参数逐项实测

3.1 基本用法:renice -n 5 -p PID

先看目标进程的当前 NI,再调整,再复核——这是 renice 的标准三步:

$ ps -o pid,ni,cmd -p 18318
    PID  NI CMD
  18318   0 sleep 1000

$ renice -n 5 -p 18318
18318 (process ID) old priority 0, new priority 5

$ ps -o pid,ni,cmd -p 18318
    PID  NI CMD
  18318   5 sleep 1000

三个关键观察:

  1. 回显格式:<PID> (process ID) old priority <旧值>, new priority <新值>——新旧值一目了然,天然就是变更记录;
  2. -n 的语义与 nice 不同:renice 的 5 是目标值(把 NI 设为 5),nice 的 -n 5 是增量(当前值 +5);
  3. ps 复核 NI=5,调整即时生效(无需重启进程)。

3.2 root 调整为负值与权限边界

把进程往更优先方向调(NI 变负)是特权操作。实测 root 尝试把 3.1 节 NI=5 的进程调到 -5:

$ renice -n -5 -p 18318
renice: failed to set priority for 18318 (process ID): Permission denied

$ ps -o pid,ni,cmd -p 18318
    PID  NI CMD
  18318   5 sleep 1000

如实记录:root 执行后 NI 仍是 5,负值没有生效。原因是本环境 root 的有效能力集不含 CAP_SYS_NICE(内核据此拦截一切"降低 nice 值"的操作),可用 /proc 实测佐证:

$ grep CapEff /proc/self/status
CapEff:	00000000a80425fb

$ ulimit -e
0

$ ulimit -H -e
0

CapEff: 00000000a80425fb 中 bit23(CAP_SYS_NICE,对应 0x800000)为 0;RLIMIT_NICE 软硬限制均为 0,通过 ulimit -e 40 抬升限制换负值的路也被封死(实测报 ulimit: scheduling priority: cannot modify limit: Operation not permitted)。

⚠️ 注意:标准 Ubuntu 服务器上 root 默认持有 CAP_SYS_NICE,同样的命令会返回 18318 (process ID) old priority 5, new priority -5 并即时生效。在降权加固的受控环境(如本实验环境)会遇到上方的 Permission denied,排查方法见第五章 Q2。

3.3 普通用户:调高允许、调低被拒

内核规则:无特权用户对自己进程只能调高(增大)nice 值,任何"调低"(包括从 10 调回 5 这种仍为正数的调整)都会被拒绝。完整实测链(演示用户 reniceu1 的进程 18337):

第一步:root 直接跨用户调整——被拒(跨 euid 修改同样需要 CAP_SYS_NICE,连调高都不行):

$ ps -o pid,user,ni,cmd -p 18337
    PID USER      NI CMD
  18337 reniceu1   0 sleep 1000

$ renice -n 6 -p 18337
renice: failed to set priority for 18337 (process ID): Operation not permitted

第二步:用户自己调高自己的进程——畅通:

$ su - reniceu1 -c 'renice -n 3 -p 18337'; echo rc=$?
18337 (process ID) old priority 0, new priority 3
rc=0

$ su - reniceu1 -c 'renice -n 9 -p 18337'; echo rc=$?
18337 (process ID) old priority 3, new priority 9
rc=0

$ ps -o pid,user,ni,cmd -p 18337
    PID USER      NI CMD
  18337 reniceu1   9 sleep 1000

第三步:用户把已提升的值(10)往回调低(到 4)——被拒,rc=1:

$ ps -o pid,user,ni,cmd -p 507
    PID USER      NI CMD
    507 reniceu1  10 sleep 1000

$ su - reniceu1 -c 'renice -n 4 -p 507'; echo rc=$?
renice: failed to set priority for 507 (process ID): Permission denied
rc=1

$ ps -o pid,user,ni,cmd -p 507
    PID USER      NI CMD
    507 reniceu1  10 sleep 1000

把三类操作汇总成权限速查表:

操作谁执行方向结果(实测)
renice -n 3 -p 自己的进程普通用户0→3 调高✅ rc=0
renice -n 9 -p 自己的进程普通用户3→9 调高✅ rc=0
renice -n 4 -p 自己的进程普通用户10→4 调低❌ Permission denied rc=1
renice -n 6 -p 他人进程root(无 CAP_SYS_NICE 时)跨用户❌ Operation not permitted
renice -n -5 -p 任意进程root(无 CAP_SYS_NICE 时)调低❌ Permission denied

3.4 -u:按用户调整(该用户名下全部进程)

-u 把目标维度从单个 PID 放大到"某用户的全部进程"。标准 root 服务器上这是批量干预的利器;本环境 root 跨用户被拒,改由用户自己执行演示:

$ renice -n 6 -u reniceu1
renice: failed to set priority for 1014 (user ID): Operation not permitted

$ su - reniceu1 -c 'renice -n 10 -u reniceu1'
1014 (user ID) old priority 0, new priority 10

$ ps -o pid,user,ni,cmd -p 507
    PID USER      NI CMD
    507 reniceu1  10 sleep 1000

结果解读:

  • 回显标识变为 <UID> (user ID)——1014 是 reniceu1 的 UID,说明这次调整覆盖了该用户名下的全部进程(此处该用户只有 507 一个进程,ps 复核 NI 已到 10);
  • root 的 -u reniceu1 报错同样指向 1014 (user ID)——报错对象是"用户维度"而非某个 PID,这是 -u/-g 与 -p 在回显上的区别。

⚠️ 注意:标准 root 服务器上 renice -n 6 -u reniceu1 会直接生效,效果等价于把该用户所有进程逐个 renice。生产上对多进程服务(如某业务账号)做整体降载时优先用 -u,避免逐 PID 枚举。

3.5 -g:按进程组调整(含"部分生效"现象解读)

-g 的目标是进程组(PGID,ps -o pgid 所示),不是用户组。它一次影响组内全部成员。先看一个失败但有玄机的案例——目标组里混着"需要降权"和"跨用户"的成员:

$ ps -o pid,ppid,pgid,ni,cmd -p 18306
    PID    PPID    PGID  NI CMD
  18306       0   18306   0 bash /root/renice-test.sh

$ renice -n 4 -g 18306
renice: failed to set priority for 18306 (process group ID): Permission denied

$ ps -o pid,ppid,pgid,ni,cmd -p 18306 -p 18318
    PID    PPID    PGID  NI CMD
  18306       0   18306   4 bash /root/renice-test.sh
  18318   18306   18306   5 sleep 1000

如实记录并解读:命令报了 Permission denied,但组内 bash 的 NI 确实从 0 变成了 4(0→4 是调高,允许),而 18318 保持 5(5→4 是调低,被拒)、组内还有跨用户成员(更不允许)。内核对进程组的 setpriority 是逐成员应用:能改的改掉,任何一处失败都会让整条命令报错并返回非零——所以"报错"不代表"全都没生效",必须用 ps 复核。

再补一个全部成员都可调高的干净案例,看成功时的回显格式:

$ ps -o pid,pgid,ni,cmd -p 88
    PID    PGID  NI CMD
     88      88   0 bash /root/final-test.sh

$ renice -n 8 -g 88
88 (process group ID) old priority 0, new priority 8

$ ps -o pid,pgid,ni,cmd -p 88 -p 99
    PID    PGID  NI CMD
     88      88   8 bash /root/final-test.sh
     99      88   8 sleep 1000

成功回显的标识是 <PGID> (process group ID);组内 bash 与 sleep 全部变为 NI=8(子进程 99 是在调整后启动、继承了组内新值)。

3.6 老式写法:省略 -n、甚至省略 -p

util-linux renice 保留了老式语法:-n 可省略(直接跟优先级数字),-p 也可省略(裸数字默认按 PID 解释):

$ renice 9 -p 18318
18318 (process ID) old priority 5, new priority 9

$ renice 12 18318
18318 (process ID) old priority 9, new priority 12

$ ps -o pid,ni,cmd -p 18318
    PID  NI CMD
  18318  12 sleep 1000

两种老式写法都能工作,效果与 renice -n 9 -p 18318 一致。建议新脚本统一用 renice -n <值> -p <PID> 的现代写法——老式写法里"数字到底是目标值还是 PID"全靠位置约定,可读性差。

3.7 多 PID 批量调整

-p 后面可以跟多个 PID,一条命令批量调整:

$ renice -n 12 -p 99 102
99 (process ID) old priority 8, new priority 12
102 (process ID) old priority 8, new priority 12

$ ps -o pid,ni,cmd -p 99,102
    PID  NI CMD
     99  12 sleep 1000
    102  12 sleep 1000

两个 PID 各自回显一行 old/new,全部成功。对照一个部分成员会失败的场景(调低方向,受限环境):

$ renice -n 2 -p 18318 18358
renice: failed to set priority for 18318 (process ID): Permission denied
renice: failed to set priority for 18358 (process ID): Permission denied

$ ps -o pid,ni,cmd -p 18318,18358
    PID  NI CMD
  18318  12 sleep 1000
  18358   4 sleep 1000

💡 要点:多目标时 renice 会逐个尝试并逐个报错(18318、18358 各一行),不会因第一个失败而中止;脚本判断结果要以返回码 + ps 复核双重确认。

3.8 错误处理:四类典型报错与返回码

实测四类最容易遇到的错误,全部 rc=1:

$ renice; echo rc=$?
renice: not enough arguments
Try 'renice --help' for more information.
rc=1

$ renice -n 5 -p 999999; echo rc=$?
renice: failed to get priority for 999999 (process ID): No such process
rc=1

$ renice -n abc -p 18318; echo rc=$?
renice: invalid priority 'abc'
Try 'renice --help' for more information.
rc=1

$ renice -n 5 -u nosuchuser9x; echo rc=$?
renice: unknown user nosuchuser9x
rc=1

报错语义细分值得注意:

场景报错阶段
不带任何参数not enough arguments用法检查,未接触内核
PID 不存在(999999)failed to get priority ... No such process先 getpriority 探测就失败
优先级非数字(abc)invalid priority 'abc'参数解析阶段
用户不存在(nosuchuser9x)unknown user用户解析阶段

对比 3.2/3.3 节的 failed to set priority ...(set 阶段失败,目标存在但权限不允许)——"get 失败"与"set 失败"的措辞差异可以帮您快速区分"目标错了"还是"权限不够"。

3.9 PR / NI 对照

调整后用 ps 的多列输出核对优先级口径:

$ ps -o pid,pri,ni,stat,cmd -p 18318,18358,18337
    PID PRI  NI STAT CMD
  18318   7  12 SN   sleep 1000
  18337  10   9 SN   sleep 1000
  18358  15   4 SN   sleep 1000

💡 技术拓展:三列解读(完整口径对照见《nice 命令详解与参数实测(Ubuntu 22.04)》3.8 节)——

列含义本环境实测换算方向
NInice 值(renice 的直接操作对象),-20~19即调整目标值越小越优先
PRI(ps)/ PR(top)工具展示口径的调度优先级ps PRI = 19 − NI;top PR = 20 + NI见方向列
STAT进程状态(S 睡眠 / R 运行 / D 不可中断 / Z 僵尸)与优先级无关—

内核对 SCHED_OTHER 进程的动态优先级为 120 + NI(100~139,越小越优先,见 sched(7))。STAT 里带 N 标记(如 SN)表示该进程的 nice 值被调整过。

四、实战示例

4.1 场景一:失控进程在线降载

某进程 CPU 占用过高又不能停,先把它调到最低优先级(NI=19),让它只在 CPU 空闲时干活:

$ renice -n 19 -p 102
102 (process ID) old priority 12, new priority 19

$ ps -o pid,ni,cmd -p 102
    PID  NI CMD
    102  19 sleep 1000

要点:全程进程不重启、连接不中断, renice 的 old/new 回显就是现成的变更记录。调高方向(12→19)无需任何特权。

4.2 场景二:降权之后的"调回"限制

场景一处理完,想把进程恢复到 NI=0——调低方向需要特权,如实记录本环境的实测结果:

$ renice -n 0 -p 102; echo rc=$?
renice: failed to set priority for 102 (process ID): Permission denied
rc=1

$ ps -o pid,ni,cmd -p 102
    PID  NI CMD
    102  19 sleep 1000

⚠️ 注意:标准 root 服务器(持有 CAP_SYS_NICE)上同样的命令会返回 102 (process ID) old priority 19, new priority 0 并即时生效。本环境因能力受限无法演示,这正是 3.2 节权限边界的实战体现——降权容易、恢复有门槛,生产上对进程降权前要评估"以后谁来调回去"。

4.3 场景三:多 PID 批量降载

一组同类工作进程需要整体降载时,一条命令搞定(3.7 节实测的调高方向批量):

$ renice -n 12 -p 99 102
99 (process ID) old priority 8, new priority 12
102 (process ID) old priority 8, new priority 12

PID 较多时配合命令替换生成清单(形态示例:renice -n 12 -p $(pgrep -f worker)),逐个回显便于逐条核对。

4.4 场景四:按用户/进程组维度批量调整

多进程服务按账号隔离时,用 -u 一次覆盖该用户全部进程(3.4 节实测):

$ su - reniceu1 -c 'renice -n 10 -u reniceu1'
1014 (user ID) old priority 0, new priority 10

同一账号下的进程树也可按进程组整体调整(3.5 节实测的成功案例):

$ renice -n 8 -g 88
88 (process group ID) old priority 0, new priority 8

选型建议:单进程用 -p;同一用户的全部进程用 -u;同一作业/脚本派生的进程组用 -g。

4.5 场景五:变更后的三步核验

调整动作完成后,固定做三步核验(均来自本文实测形态):

$ ps -o pid,ni,cmd -p 18318
    PID  NI CMD
  18318  12 sleep 1000

$ ps -o pid,pri,ni,stat,cmd -p 18318,18358,18337
    PID PRI  NI STAT CMD
  18318   7  12 SN   sleep 1000
  18337  10   9 SN   sleep 1000
  18358  15   4 SN   sleep 1000

第一步回读 NI 确认目标值到位;第二步带 PRI/STAT 看调度口径与进程状态(N 标记确认被 nice 过);第三步(可选)在 top 里观察一段时间内该进程的 CPU 份额变化——NI 只在 CPU 争抢时体现效果(见第五章 Q5,同 nice 篇口径)。

五、注意事项与常见问题

Q1:renice 和 nice 怎么分工?用了 renice 还需要 nice 吗? 互为补充:nice 在启动时预设(只能影响它自己拉起的命令),renice 在运行中改判(还能按 -u/-g 批量)。已经跑起来的进程想改优先级只能 renice——nice 对已运行进程无能为力(详见 nice 篇 3.9 节实测)。两者对"调低"的权限要求完全一致(CAP_SYS_NICE/RLIMIT_NICE)。

Q2:为什么 root 执行 renice -n -5 也报 Permission denied? 内核要求"降低 nice 值"(含跨用户修改)必须持有 CAP_SYS_NICE。本环境实测 root 的 CapEff: 00000000a80425fb 不含该位(3.2 节),RLIMIT_NICE 软硬限制也都是 0,ulimit -e 40 抬升受限同样被拒。排查三步:grep CapEff /proc/self/status 对照 CAP_SYS_NICE(bit23,0x800000)→ ulimit -e 与 ulimit -H -e 看限制 → 确认目标进程的属主(跨用户必被拒)。标准服务器上 root 默认持有该能力,直接生效。

Q3:为什么把进程调"高优先级"很容易,想调回来却报错? 内核把 setpriority 的方向做了不对称限制:调高 nice 值(让路)人人可做、随时可做;调低 nice 值(插队)是特权操作。这形成事实上的"不可逆":普通用户把进程降到 19 后自己永远调不回来,root 调低也要 CAP_SYS_NICE(见 4.2 节实测 rc=1)。生产建议:降权前想清楚恢复路径;对关键服务避免用普通账号做降权操作。

Q4:renice 属于哪个软件包?为什么它的 help/报错风格和 nice 不一样? renice 来自 util-linux 2.37.2(renice from util-linux 2.37.2,2.3 节实测),nice 来自 GNU coreutils 8.32——两个独立上游,所以 help 排版(Usage 块 vs 逐行描述)、版本输出(一行短句 vs 版权块)、报错措辞(failed to set priority vs cannot set niceness)都不同。底层都是 setpriority(2),语义一致。

Q5:renice 改了 NI,为什么看不出来性能变化? NI 只在 CPU 争抢时起作用。系统空闲时高 NI 进程照样满速跑;瓶颈在内存/磁盘/网络时调 NI 无效。验证调度效果要在 CPU 饱和的场景下对比 top 中同优先级进程的 CPU% 占比,或用 perf 类工具观测调度延迟。

Q6:报错信息里 failed to get priority 和 failed to set priority 有什么区别? get 失败 = 目标根本不存在或不可见(如 3.8 节的 PID 999999);set 失败 = 目标存在但当前身份无权做该调整(3.2/3.3 节的 Permission denied / Operation not permitted)。看到 get 失败先查目标写没写对,看到 set 失败再查权限与方向。

六、参考链接