ss -m 的 mem: 显示内核为 socket 分配的收发缓冲区当前占用字节数,非上限值;rmem 是接收队列已排队数据量,wmem 是发送队列未处理数据量,udp 的 wmem 恒为 0。

ss -m 看 socket 内存时,mem: 里那些数字到底对应啥
直接看 ss -m 输出里的 mem: 行,容易误以为是“当前占用内存”,其实它展示的是内核为该 socket 分配的各层缓冲区大小(单位字节),不是 RSS 或进程实际内存开销。
常见错误现象:发现某个连接 mem: rmem:131072 wmem:131072,就以为占了 256KB 内存——但这是收发缓冲区上限(sk->sk_rcvbuf/sk->sk_sndbuf),实际只在有数据排队时才真实占用;空闲连接几乎不耗内存。
-
rmem是接收队列已排队字节数(不是上限),rcv_space才是当前通告窗口大小 -
wmem是发送队列中尚未被协议栈处理的数据量(比如还在sk_write_queue里),不含已交给网卡但未确认的部分 - UDP socket 的
wmem永远是 0,因为无重传队列;TCP 的wmem高可能意味着对端接收慢或丢包 - 用
ss -m state established过滤后,再按wmem排序:ss -m state established | sort -k8,8n(第8字段通常是 wmem)
ss -o 显示 timer 信息时,“on” 和 “off” 到底表示什么状态
ss -o 的 timer 字段(如 timer:(keepalive,15min,0))不是开关状态,而是描述该 socket 当前启用的定时器类型和剩余时间。所谓 “on/off” 是内核输出的简写,on 表示定时器已启动并计时中,off 表示未激活(比如刚建连还没到 keepalive 起始时间)。
容易踩的坑:看到 timer:(on,15min,0) 就以为 keepalive 正在发包——其实括号里第三个数字是重试次数,0 表示尚未触发超时重试;只有变成 (on,15min,1) 才说明第一次重传已失败。
- TCP 常见 timer 类型:
keepalive(保活)、timewait(TIME_WAIT 倒计时)、persist(零窗口探测)、retrans(重传) -
ss -o state time-wait会显示timer:(timewait,sec:30),这个 30 秒是内核tcp_fin_timeout值,不是固定 2MSL - UDP socket 永远不会显示 timer,哪怕绑定了
SO_RCVTIMEO—— 因为超时是用户态控制的,内核 socket 层无定时器
ss -p 需要 root 权限才能显示进程名,但普通用户也能绕过部分限制
ss -p 默认要求 CAP_NET_ADMIN 或 root,否则报错 Permission denied。这不是设计缺陷,而是因为读取 /proc/[pid]/fd/ 下的 socket 符号链接需要目标进程的 ptrace 权限(由 /proc/sys/kernel/yama/ptrace_scope 控制)。
非 root 用户仍有办法获取部分信息:
- 如果目标进程是自己启动的(UID 匹配),
ss -p可以正常显示进程名,无需 root - 用
ss -tuln先拿到监听端口和 inode,再手动查lsof -i :端口号(需安装 lsof,且依赖 /proc 权限) - 检查
/proc/net/{tcp,tcp6,udp,udp6}中的inode列,然后遍历/proc/[0-9]*/fd/找符号链接指向socket:[inode]—— 但普通用户只能遍历自己进程的 fd 目录 - systemd 系统下,
sudo ss -tulnp比sudo netstat -tulpn更快,因为不依赖 /proc/net 的文本解析,直接读取内核 sock_diag 接口
混用 -m/-o/-p 时,字段顺序和兼容性要注意
ss -mop 看起来方便,但不同内核版本输出字段数不一致:4.15+ 内核在 -m 后会多出 ino(inode 号)字段,而 -p 附加的进程信息会插在最后,导致列偏移错乱。用 awk 或 cut 提取字段时极易出错。
真实使用场景中,更稳妥的做法是分步查,而不是堆参数:
- 先用
ss -tuln state established | head -20定位可疑连接 - 记下其 inode(最后一列),再单独查:
ss -m -o -i "inode:123456"(注意引号和空格) - 想关联进程?用
ls -l /proc/*/fd/ 2>/dev/NULL | grep 'socket:[123456]',比-p更可靠 - centos 7(内核 3.10)不支持
-o的完整 timer 显示,会输出timer:(off)即使 keepalive 已启用——得看/proc/sys/net/ipv4/tcp_keepalive_*配置是否生效
最常被忽略的一点:socket 的内存、timer、进程三类信息来自内核不同子系统(sock, timer, task_struct),ss 是一次性发起多个 netlink 查询再拼装结果,中间若有进程退出或连接关闭,可能看到 “内存值正常但进程已不存在” 的情况——这不是 bug,是竞态窗口内的正常现象。