news 2026/10/14 3:14:46

Linux 系统调试学习2

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 系统调试学习2

1、ps、top、htop分别干什么?

先记这个区别:

ps = 看“当前这一刻”的进程快照 top = 实时刷新系统进程状态 htop = 更友好的交互式 top

所以:

想快速查一个进程有没有启动 → ps 想持续观察 CPU / 内存 → top 想更方便地看线程、排序、搜索 → htop

ps aux

常见列:

USER PID %CPU %MEM VSZ RSS STAT START COMMAND

你不用全背。

现阶段重点:

PID %CPU %MEM RSS STAT COMMAND
R = running / runnable
S = sleeping
D = uninterruptible sleep
T = stopped
Z = zombie

如果一个网络接收线程对应的进程大多数时间:

S

很正常。

因为它可能正在:

recv poll epoll_wait condition_variable

等待事件。


zombie

僵尸进程:

Z

不是说进程还在正常执行。

而是:

子进程已经退出,但父进程还没有回收它的退出状态。

可以理解:

child 已经死了 ↓ 内核还保留一小份退出信息 ↓ parent 还没 wait()

所以 zombie:

通常不占大量 CPU / 内存

但如果大量出现:

说明父进程的子进程管理有问题

运行:

top

通常上面会看到:

load average Tasks CPU Memory Swap

下面是进程列表。

你现阶段优先看:

%CPU %MEM RES PID COMMAND

比如:

PID %CPU %MEM RES COMMAND 4321 98.5 2.1 300M gmr_node 4500 3.0 1.0 120M robot_output

那第一反应:

gmr_node 明显是 CPU 热点

然后继续查:

线程 函数

如果只关心一个进程:

top -p 4321

这样界面干净很多。

特别适合现场:

只盯 robot_control
top -H -p 4321

意思:

看这个进程里的线程。

例如:

TID %CPU 4321 5% 4322 95% 4323 1% 4324 3%

马上知道:

线程 4322

最忙。

然后下一步可以:

perf gdb strace

继续看它在干什么。

这就是你之前 perf 那节的链路:

进程高 ↓ top -H ↓ 线程高 ↓ perf ↓ 函数高
某线程 100%

往往意味着:

这个线程几乎一直在执行,没有怎么阻塞。

如果它本来应该:

等待 UDP

结果却 100%,就很可疑。

可能是:

busy loop EAGAIN 重试 轮询错误 while(true)

htop的价值

htop比top更友好。

运行:

htop

一般可以:

搜索进程 按 CPU 排序 按内存排序 展开线程 树状查看父子关系

对初学者很适合。

比如你可以更直观看:

ros2 launch ├── node_a ├── node_b └── node_c

这种父子关系。


ps 看线程

例如:

ps -T -p 4321

或者:

ps -L -p 4321

可以看到线程。

如果想更详细:

ps -L -p 4321 -o pid,tid,psr,pcpu,stat,comm

其中:

tid = 线程 ID
psr = 当前/最近运行在哪个 CPU 上
pcpu = CPU 占用

这会和后面的:

CPU affinity

直接连接。


怎么知道进程什么时候启动?

可以:

ps -o pid,lstart,etime,cmd -p 4321

其中:

lstart = 启动时间
etime = 已运行多久

这很适合排查:

程序是不是刚刚自动重启过?

例如你以为它运行 8 小时,

结果:

etime = 00:02:15

说明:

2 分钟前刚重启

那就要继续查:

systemd 崩溃 watchdog

查看 CPU 核数?

简单:

nproc

例如:

8

说明有 8 个逻辑 CPU。

也可以:

lscpu

看更详细信息。


查看进程树

常用:

pstree -p

你可能看到:

systemd(1) └─ros2(3000) ├─mocap_node(3100) ├─gmr_node(3101) └─robot_output(3102)

这对 ROS2 launch/systemd 服务排查非常直观。

pgrep -a robot_control

找到 PID。

然后:

ps -o pid,ppid,etime,stat,%cpu,%mem,rss,args -p PID

一次看:

PID 父进程 运行时间 状态 CPU 内存 完整启动参数

这个非常适合机器人现场。


只看网络相关系统调用

strace -e trace=network -p 4321

这样重点看:

socket bind connect accept send recv

只看文件系统调用

例如配置文件加载失败:

strace -e trace=file ./robot_control

你可能看到:

openat(..., "/etc/robot/config.yaml", ...) = -1 ENOENT

这说明:

No such file or directory

可能程序其实在错误目录找配置。

这类问题非常常见。


futex

你以后 strace 非常容易看到:

futex(...)

先不要怕。

它和:

mutex condition_variable 线程同步

密切相关。

可以粗略理解:

Linux 用户态线程在等待锁或条件变化时,底层经常会使用 futex。

所以如果程序卡住,多个线程都:

futex(... FUTEX_WAIT ...)

你应该开始怀疑:

是不是在等 mutex / condition_variable

甚至可能:

deadlock

-T特别适合看谁卡得久

例如:

recvfrom(...) <0.000012> openat(...) <0.000030> connect(...) <10.001234>

一看:

connect

花了 10 秒。

所以:

strace 不只是看“调用了什么”,还能帮助看“系统调用卡了多久”。


保存 strace 日志

例如:

strace -o trace.log -p 4321

日志保存到:

trace.log

现场问题特别适合。

还可以:

strace -ff -o trace -p 4321

多线程/子进程场景会生成多个 trace 文件。

现在知道即可。

程序崩了 → gdb / core dump
程序卡了 → strace + gdb
CPU高 → top -H + perf
内存涨 → RSS + ASan/Valgrind
系统调用异常 → strace
线程竞争 → TSan

这就是你现在的完整排障工具链。


2、systemd

systemd = Linux 上用来管理系统服务和进程生命周期的服务管理器。

它能帮你做:

开机自启 ↓ 启动程序 ↓ 监控是否退出 ↓ 异常时自动重启 ↓ 统一日志 ↓ 正常 stop ↓ 管理依赖关系

所以机器人上的:

robot_driver controller diagnostics network_bridge

很适合交给 systemd 管。

& = shell后台运行

而:

systemd = 服务生命周期管理

完全不是一个层级。

假设文件放在:

/etc/systemd/system/robot_control.service

然后:

sudo systemctl daemon-reload

告诉 systemd:

unit 文件更新了,重新加载。

启动:

sudo systemctl start robot_control

查看:

systemctl status robot_control

停止:

sudo systemctl stop robot_control

重启:

sudo systemctl restart robot_control

这几个非常常用。


Type=simple

先简单理解:

systemd 认为ExecStart启动的进程就是服务主进程。

对于很多普通机器人程序:

Type=simple

已经够用。

以后还会看到:

notify forking oneshot

现在不用展开。

对于:

Type=simple

systemd 直接跟踪:

ExecStart

启动的进程。

所以:

systemctl status robot_control

能看到:

Main PID

这也是为什么前面说:

启动脚本里使用 exec

会让进程关系更干净。

3、Linux

Linux 权限决定“哪个用户/进程,可以对哪个资源做什么”。

dialout 组

sudo usermod -aG dialout $USER

意思:

把当前用户加入dialout组。

之后重新登录,让组信息生效。

再:

groups

确认有:

dialout

这时候你的进程就可以:

以普通用户身份 ↓ 访问 /dev/ttyUSB0

比:

sudo ./robot_driver

更合理。

udev

udev = Linux 用来管理设备节点和设备事件的一套机制。

比如你插入 USB 串口:

USB 设备插入 ↓ Linux 内核识别 ↓ udev 处理 ↓ 创建 /dev/ttyUSB0 ↓ 设置 owner / group / mode ↓ 甚至创建稳定别名

所以:

/dev/ttyUSB0

不是你手工创建的。

很多时候是:

udev

帮你创建和配置。

udev rule 是一组规则:

当某种设备出现时,应该怎么命名、怎么设权限、属于哪个组。

规则一般放在:

/etc/udev/rules.d/

例如:

99-robot.rules

为什么 udev 比 chmod 更适合工程部署?

因为:

插拔设备 ↓ udev 自动匹配 ↓ 自动应用权限

你不需要每次:

sudo chmod ...

所以:

chmod = 临时人工操作

而:

udev rule = 可重复、可部署、自动化配置

这就是工程上的区别。

怎么查 USB 设备的 Vendor/Product ID?

最常用:

lsusb

例如:

Bus 001 Device 005: ID 0403:6015 Future Technology Devices...

这里:

0403

是 vendor ID。

6015

是 product ID。

这类信息可以用于写 udev rule。


udevadm info

比如:

udevadm info -a -n /dev/ttyUSB0

它会输出设备属性。

你可以找到:

idVendor idProduct serial manufacturer

然后选择稳定属性写规则。


udev rule 改完怎么生效?

常见:

sudo udevadm control --reload-rules

然后:

sudo udevadm trigger

或者直接重新插拔设备。

再:

ls -l /dev/robot_imu

确认规则是否生效。如果规则没生效怎么查?

可以:

udevadm info -a -n /dev/ttyUSB0

确认你匹配的属性到底在哪一层。

因为:

ATTR

和:

ATTRS

含义有差别。

现阶段不需要钻语法细节。

你先建立排障流程:

设备存在吗? ↓ ls -l 权限是什么? ↓ udevadm info 看属性 ↓ rule 是否匹配? ↓ reload ↓ 重新插拔

capability

Linux 不只有:

普通用户 root

两档。

还可以把 root 的能力拆成很多:

capabilities

比如:

CAP_NET_ADMIN CAP_SYS_NICE CAP_IPC_LOCK

这些以后实时控制也会碰到。

例如:

SCHED_FIFO

高实时优先级可能需要:

CAP_SYS_NICE

mlockall某些配置下可能涉及:

MEMLOCK limit

网络接口配置可能涉及:

CAP_NET_ADMIN

所以:

能力可以细分授权,而不是所有事都 sudo root。


目录权限里的 x 是什么意思?

这里很容易踩坑。

对普通文件:

x

一般是:

execute

但对目录:

x

更接近:

允许进入/穿过这个目录。

例如:

/home/robot/config/

即使:

robot.yaml

本身可读,

但上级目录没有执行权限:

程序还是可能打不开

所以权限问题不能只看目标文件。


udev 还能做什么?

除了:

设置权限 创建 symlink

它还可以:

根据设备插拔触发规则 设置属性 设备命名

不过机器人项目里你现阶段最重要的是:

稳定命名 + 访问权限

这两个


4、权限

ip addr:先看网卡和 IP

最常用:

ip addr

或者:

ip a

你会看到类似:

2: enp3s0: inet 192.168.1.10/24

这里:

enp3s0 = 网卡接口名 192.168.1.10 = IP /24 = 子网前缀

机器人现场第一步经常就是:

目标网卡到底有没有正确 IP?


ip link:看网卡是不是 UP

执行:

ip link

可能看到:

enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP>

重点:

UP

表示接口被启用。

LOWER_UP

通常说明物理链路也起来了。

如果没有:

LOWER_UP

你就要怀疑:

网线 交换机 网口 设备供电

而不是先查应用程序。


手工启用网卡

例如:

sudo ip link set enp3s0 up

关闭:

sudo ip link set enp3s0 down

这只是接口状态控制。

不是配置 IP。


临时设置静态 IP

例如:

sudo ip addr add 192.168.1.10/24 dev enp3s0

注意这是:

临时配置

重启后通常不会永久保留。

生产系统一般用:

NetworkManager netplan systemd-networkd

等做持久配置。

ping到底验证了什么?

例如:

ping 192.168.1.20

如果通:

说明 IP 层基本可达

但注意:

ping 通 ≠ UDP/TCP 应用一定正常。

因为 ping 用的是:

ICMP

不是:

TCP UDP

所以只能说明:

网络路径大体可达

不能证明:

你的端口打开 程序在监听 防火墙没拦 UDP 应用协议正确

为什么 ping 不通,也不一定说明完全不通?

有些设备或防火墙:

禁止 ICMP

但:

TCP/UDP 业务端口仍然正常

所以:

ping

只是网络排查工具之一。

不能作为唯一判断。


ss:查端口最重要

你前面已经见过:

ss -ltnp

看 TCP 监听。

拆开:

-l = listening -t = TCP -n = 不解析名字 -p = 显示进程

例如:

LISTEN 0 128 0.0.0.0:5555 users:(("robot_server",pid=4321,fd=8))

说明:

robot_server PID 4321 fd 8 正在监听 TCP 5555
ss -lunp

其中:

-u = UDP

比如:

0.0.0.0:7014

说明程序已经 bind 7014。

这对你的动捕 UDP 排障特别关键。


0.0.0.0是什么意思?

如果服务绑定:

0.0.0.0:7014

一般表示:

接受本机多个 IPv4 接口上发到 7014 的流量。

如果绑定:

192.168.1.10:7014

那通常只监听这个地址。

所以:

bind 地址

也是通信是否正常的重要因素。


127.0.0.1是什么意思?

127.0.0.1

是:

localhost 回环地址

如果服务只绑定:

127.0.0.1:5555

那么:

本机程序可以访问 远端机器通常访问不了

这是一个非常常见的配置问题。


TCP 怎么简单测端口?

如果你想确认:

192.168.1.20:5555

能不能建立 TCP 连接,可以用:

nc -vz 192.168.1.20 5555

成功可能看到:

succeeded

这说明:

TCP 路径和服务监听基本正常

UDP 为什么不能像 TCP 那么简单验证?

因为 UDP:

没有连接建立过程

你发一个包:

不一定有回应

所以:

“我 sendto 成功了”

只能说明:

本地内核接受了这个数据发送请求。

不代表:

对端一定收到了

这就是 UDP 排查为什么更依赖抓包和应用层统计。


ethtool

例如:

sudo ethtool enp3s0

可以看:

Link detected Speed Duplex Auto-negotiation

例如:

Speed: 1000Mb/s Duplex: Full Link detected: yes

对于机器人有线网络很实用。


Full Duplex

简单理解:

Full Duplex = 可以同时收和发

现代以太网通常都是全双工。

如果协商异常:

速度或双工不一致

可能导致:

大量重传 吞吐下降 奇怪网络问题

比如服务:

机器人电脑 192.168.1.10

如果你在本机测试:

nc 127.0.0.1 5555

成功。

不能证明:

远端 192.168.1.20

也能连接。

还需要测试:

nc 192.168.1.10 5555

并从另一台机器实际测试。


一个典型 UDP 动捕排障流程

假设:

动捕发送端 → 192.168.10.20:7014

你的机器人:

应该接收

第一步:

ip addr

确认机器人网卡是不是:

192.168.10.x/24

第二步:

ip link

确认:

UP LOWER_UP

第三步:

ss -lunp

确认:

7014

真的被你的进程 bind。

第四步:

strace -e trace=network -p PID

看:

recvfrom

有没有数据返回。

这样就能逐层缩小问题。


TCPConnection refused

例如:

connect(...) → Connection refused

通常意味着:

目标 IP 可达 但目标端口上没有服务监听

或者明确被拒绝。

这和:

Connection timed out

不一样。

设备网络 → EtherCAT / CAN / UDP 传感器 机器人内部通信 → ROS2 / ZMQ 外部网络 → SSH / Wi-Fi / 调试 / 远程监控
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 3:14:45

AscendNPU-IR 入门指南:基于 MLIR 的昇腾亲和算子编译中间表示

编译器人工智能AscendCANN 【免费下载链接】AscendNPU-IR AscendNPU-IR是基于MLIR&#xff08;Multi-Level Intermediate Representation&#xff09;构建的&#xff0c;面向昇腾亲和算子编译时使用的中间表示&#xff0c;提供昇腾完备表达能力&#xff0c;通过编译优化提升昇腾…

作者头像 李华
网站建设 2026/10/14 3:14:24

Unity Windows原生窗口控制:无边框与状态栏适配实战

1. 项目概述&#xff1a;为什么在Unity里“动”Windows原生窗口是个刚需做Unity桌面应用的开发者&#xff0c;尤其是开发工具类、工业控制面板、数字孪生看板或者需要深度集成Windows系统行为的项目时&#xff0c;迟早会撞上这个墙&#xff1a;Unity默认的窗口管理太“温柔”了…

作者头像 李华
网站建设 2026/10/14 3:13:42

Python爬虫必备:同步与异步HTTP库全解析

在进行数据分析以及竞品调研的时候, 首先需要明确, 最基础也是最关键的一个步骤, 就是必须把数据从网络上面抓取下来。而在整个过程中里最常用的两个 HTTP 库是同步的和异步的这两个&#xff08;具体的库名称可能需要读者自行对应上下文填补空缺&#xff09;, 这两者加在一起就…

作者头像 李华
网站建设 2026/10/14 3:13:22

Coze智能体搭建实战:从零跑通工作流与Web应用

1. 这不是“又一个Coze教程”&#xff0c;而是一份能让你真正跑通第一个智能体的实操手记我带过不少刚接触Coze的朋友&#xff0c;从某高校实验室的研究生&#xff0c;到某公司转型做AI产品的运营同事&#xff0c;再到完全没写过代码的自由职业者。他们问得最多的问题从来不是“…

作者头像 李华