背景
放假的时候发现 java总是使用多余 堆区+堆外内存的情况当时理解有tcp以及有碎片本次通过大模型验证了tcp内存的使用情况感觉模型真的好厉害生成的脚本很不错
脚本执行结果
脚本生成方式
使用 kimi2.5 通过大概十几轮次的对话完成了最终的脚本效果还算良好centos/银河麒麟均可以使用了
脚本全文
#!/bin/sh# tcp_memory_final.sh - 最终优化版# 颜色设置if [ -t 1 ] && [ -n "$TERM" ] && [ "$TERM" != "dumb" ]; then RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'else RED=''; GREEN=''; YELLOW=''; BLUE=''; CYAN=''; BOLD=''; NC=''fihr() { b=$1; [ -z "$b" ] || [ "$b" = "0" ] && { echo "0B"; return; } [ $b -ge 1073741824 ] && echo "$((b/1073741824)).$((b%1073741824/107374182))G" && return [ $b -ge 1048576 ] && echo "$((b/1048576)).$((b%1048576/104858))M" && return [ $b -ge 1024 ] && echo "$((b/1024)).$((b%1024/103))K" && return echo "${b}B"}read_sysctl() {local key="$1"local val=""local proc_path="/proc/sys/${key//./\/}" [ -f "$proc_path" ] && val=$(cat "$proc_path"2>/dev/null)if [ -z "$val" ] && command -v sysctl >/dev/null2>&1; then val=$(sysctl -n "$key"2>/dev/null) fi echo "${val:-N/A}"}main() { echo "${CYAN}扫描中...${NC}" TMP="${TMP:-/tmp}" DATA="$TMP/tcpdata.$$" SORT="$TMP/tcpsort.$$" ss -mtinp 2>/dev/null | awk ' BEGIN { prev=""; has_pid=0 } { line = $0 if (line ~ /skmem:/ || (line ~ /^[ \t]/ && line ~ /r[0-9]+,rb/)) { pid = "" if (has_pid && match(prev, /pid=[0-9]+/)) pid = substr(prev, RSTART+4, RLENGTH-4) if (pid == "" && match(line, /pid=[0-9]+/)) pid = substr(line, RSTART+4, RLENGTH-4) if (pid == "" || pid == "0") { prev=line; has_pid=0; next } state = "OTHER" if (prev ~ /ESTAB/ || line ~ /ESTAB/) state = "ESTAB" else if (prev ~ /TIME-WAIT/ || prev ~ /TIME_WAIT/ || line ~ /TIME/) state = "TW" else if (prev ~ /CLOSE-WAIT/ || prev ~ /CLOSE_WAIT/ || line ~ /CLOSE-WAIT/) state = "CW" else if (prev ~ /SYN-RECV/ || prev ~ /SYN_RECV/ || line ~ /SYN-RECV/) state = "SR" else if (prev ~ /FIN-WAIT/ || prev ~ /FIN_WAIT/ || line ~ /FIN-WAIT/) state = "FW" else if (prev ~ /LAST-ACK/ || prev ~ /LAST_ACK/ || line ~ /LAST-ACK/) state = "LAST" else if (prev ~ /CLOSING/ || line ~ /CLOSING/) state = "CLOSING" rb = 0; tb = 0 if (match(line, /rb[0-9]+/)) rb = substr(line, RSTART+2, RLENGTH-2) else if (match(line, /rb:[0-9]+/)) rb = substr(line, RSTART+3, RLENGTH-3) if (match(line, /tb[0-9]+/)) tb = substr(line, RSTART+2, RLENGTH-2) else if (match(line, /tb:[0-9]+/)) tb = substr(line, RSTART+3, RLENGTH-3) if (tb == 0 && match(line, /wmem[0-9]+/)) tb = substr(line, RSTART+4, RLENGTH-4) if (rb == 0 && match(line, /rmem[0-9]+/)) rb = substr(line, RSTART+4, RLENGTH-4) gsub(/[^0-9]/, "", rb); gsub(/[^0-9]/, "", tb) total = rb + tb if (total > 0) print state "|" pid "|" total "|" rb "|" tb has_pid = 0 } else { prev = line has_pid = (line ~ /pid=/) } }' > "$DATA" LINES=$(wc -l < "$DATA" 2>/dev/null | tr -d ' ') [ "$LINES" = "0" ] || [ -z "$LINES" ] && { echo "${RED}错误: 未解析到数据${NC}"; rm -f "$DATA"; return 1; } echo "${CYAN}聚合 $LINES 条连接...${NC}" awk -F'|' '{ s=$1; p=$2; t=$3; r=$4; b=$5 if (!(p in pn)) { pn[p] = "unknown" cmd = "cat /proc/" p "/comm 2>/dev/null" if ((cmd | getline x) > 0) pn[p] = x close(cmd) tc[p]=0; tm[p]=0; ec[p]=0; em[p]=0; wc[p]=0; wm[p]=0; cc[p]=0; cm[p]=0 sc[p]=0; sm[p]=0; fc[p]=0; fm[p]=0; lc[p]=0; lm[p]=0; oc[p]=0; om[p]=0 } tc[p]++; tm[p]+=t if (s=="ESTAB") { ec[p]++; em[p]+=t } else if (s=="TW") { wc[p]++; wm[p]+=t } else if (s=="CW") { cc[p]++; cm[p]+=t } else if (s=="SR") { sc[p]++; sm[p]+=t } else if (s=="FW") { fc[p]++; fm[p]+=t } else if (s=="LAST") { lc[p]++; lm[p]+=t } else { oc[p]++; om[p]+=t } } END { for (x in tc) { printf "%s|%s|%d|%d|%d|%d|%d|%d|%d|%d|%d|%d|%d|%d|%d|%d|%d|%d\n", x, pn[x], tc[x], tm[x], ec[x], em[x], wc[x], wm[x], cc[x], cm[x], sc[x], sm[x], fc[x], fm[x], lc[x], lm[x], oc[x], om[x] } }' "$DATA" | sort -t'|' -k4 -nr > "$SORT" rm -f "$DATA" # Top10表格 echo "" printf "${BOLD}${BLUE}" echo "╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗" echo "║ TCP 内存使用 Top 10 进程 ║" echo "╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝" printf "${NC}\n" printf "${BOLD}${YELLOW}%-4s | %-20s | %6s | %12s | %6s | %12s | %6s | %12s | %6s | %12s | %8s${NC}\n" \ "排名" "进程名(PID)" "总连接" "总内存" "ESTAB" "ESTAB内存" "TW" "TW内存" "CW" "CW内存" "可读" printf "${BOLD}${YELLOW}%-4s | %-20s | %6s | %12s | %6s | %12s | %6s | %12s | %6s | %12s | %8s${NC}\n" \ "----" "--------------------" "------" "------------" "------" "------------" "------" "------------" "------" "------------" "--------" R=0 T10_TC=0; T10_TM=0; T10_EC=0; T10_EM=0; T10_WC=0; T10_WM=0; T10_CC=0; T10_CM=0 ALL_TC=0; ALL_TM=0; ALL_EC=0; ALL_EM=0; ALL_WC=0; ALL_WM=0; ALL_CC=0; ALL_CM=0 ALL_SC=0; ALL_SM=0; ALL_FC=0; ALL_FM=0; ALL_LC=0; ALL_LM=0; ALL_OC=0; ALL_OM=0 PC=0 while IFS='|' read -r P PN TC TM EC EM WC WM CC CM SC SM FC FM LC LM OC OM; do PC=$((PC+1)) ALL_TC=$((ALL_TC+TC)); ALL_TM=$((ALL_TM+TM)) ALL_EC=$((ALL_EC+EC)); ALL_EM=$((ALL_EM+EM)) ALL_WC=$((ALL_WC+WC)); ALL_WM=$((ALL_WM+WM)) ALL_CC=$((ALL_CC+CC)); ALL_CM=$((ALL_CM+CM)) ALL_SC=$((ALL_SC+SC)); ALL_SM=$((ALL_SM+SM)) ALL_FC=$((ALL_FC+FC)); ALL_FM=$((ALL_FM+FM)) ALL_LC=$((ALL_LC+LC)); ALL_LM=$((ALL_LM+LM)) ALL_OC=$((ALL_OC+OC)); ALL_OM=$((ALL_OM+OM)) if [ $R -lt 10 ]; then R=$((R+1)) T10_TC=$((T10_TC+TC)); T10_TM=$((T10_TM+TM)) T10_EC=$((T10_EC+EC)); T10_EM=$((T10_EM+EM)) T10_WC=$((T10_WC+WC)); T10_WM=$((T10_WM+WM)) T10_CC=$((T10_CC+CC)); T10_CM=$((T10_CM+CM)) DN="$PN($P)" if [ ${#DN} -gt 20 ]; then DN=$(printf"%.17s..)""$DN")else DN=$(printf"%-20s""$DN") fiprintf"${CYAN}[%2d]${NC} | %s | %6d | %12d | %6d | %12d | %6d | %12d | %6d | %12d | ${GREEN}%8s${NC}\n" \"$R""$DN""$TC""$TM""$EC""$EM""$WC""$WM""$CC""$CM""$(hr $TM)" fi done < "$SORT" rm -f "$SORT"printf"${BOLD}${YELLOW}%-4s | %-20s | %6s | %12s | %6s | %12s | %6s | %12s | %6s | %12s | %8s${NC}\n" \"----""--------------------""------""------------""------""------------""------""------------""------""------------""--------"printf"${BOLD}${RED}%-4s${NC} | ${BOLD}%-20s${NC} | ${BOLD}${RED}%6d${NC} | ${BOLD}%12d${NC} | ${BOLD}%6d${NC} | ${BOLD}%12d${NC} | ${BOLD}%6d${NC} | ${BOLD}%12d${NC} | ${BOLD}%6d${NC} | ${BOLD}%12d${NC} | ${GREEN}${BOLD}%8s${NC}\n" \"TOP10""合计 ""$T10_TC""$T10_TM""$T10_EC""$T10_EM""$T10_WC""$T10_WM""$T10_CC""$T10_CM""$(hr $T10_TM)"# 全进程合计 echo ""printf"${BOLD}${YELLOW}全进程合计 (ALL PROCESSES):${NC}\n"printf"${BOLD}%-20s | %10s | %15s | %12s${NC}\n""类别""连接数""内存(字节)""可读"printf"${BOLD}%-20s | %10s | %15s | %12s${NC}\n""--------------------""----------""---------------""------------"printf"%-20s | %10d | %15d | ${GREEN}%12s${NC}\n""ESTABLISHED""$ALL_EC""$ALL_EM""$(hr $ALL_EM)"printf"%-20s | %10d | %15d | ${GREEN}%12s${NC}\n""TIME-WAIT""$ALL_WC""$ALL_WM""$(hr $ALL_WM)"printf"%-20s | %10d | %15d | ${GREEN}%12s${NC}\n""CLOSE-WAIT""$ALL_CC""$ALL_CM""$(hr $ALL_CM)"printf"%-20s | %10d | %15d | ${GREEN}%12s${NC}\n""SYN-RECV""$ALL_SC""$ALL_SM""$(hr $ALL_SM)"printf"%-20s | %10d | %15d | ${GREEN}%12s${NC}\n""FIN-WAIT""$ALL_FC""$ALL_FM""$(hr $ALL_FM)"printf"%-20s | %10d | %15d | ${GREEN}%12s${NC}\n""LAST-ACK""$ALL_LC""$ALL_LM""$(hr $ALL_LM)"printf"%-20s | %10d | %15d | ${GREEN}%12s${NC}\n""其他状态""$ALL_OC""$ALL_OM""$(hr $ALL_OM)"printf"${BOLD}%-20s | %10s | %15s | %12s${NC}\n""--------------------""----------""---------------""------------"printf"${BOLD}${RED}%-20s${NC} | ${BOLD}${RED}%10d${NC} | ${BOLD}${RED}%15d${NC} | ${GREEN}${BOLD}%12s${NC}\n""TOTAL ALL""$ALL_TC""$ALL_TM""$(hr $ALL_TM)" echo ""printf"${BOLD}${YELLOW}进程总数: %3d | 连接总数: %4d | 内存总计: %s${NC}\n""$PC""$ALL_TC""$(hr $ALL_TM)"}kernel_info() { echo "" printf "${BOLD}${BLUE}" echo "╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗" echo "║ 核心 TCP 内核参数 ║" echo "╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝" printf "${NC}\n" # 参数列表 set -- \ "net.ipv4.ip_local_port_range:端口范围" \ "net.ipv4.tcp_rmem:TCP接收缓冲" \ "net.ipv4.tcp_wmem:TCP发送缓冲" \ "net.core.rmem_max:最大接收缓冲" \ "net.core.wmem_max:最大发送缓冲" \ "net.core.rmem_default:默认接收缓冲" \ "net.core.wmem_default:默认发送缓冲" \ "net.core.somaxconn:监听队列" \ "net.ipv4.tcp_max_syn_backlog:SYN队列" \ "net.ipv4.tcp_tw_reuse:TIME-WAIT重用" \ "net.ipv4.tcp_tw_recycle:TIME-WAIT回收" \ "net.ipv4.tcp_max_tw_buckets:TIME-WAIT桶限制" \ "net.ipv4.tcp_fin_timeout:FIN超时" \ "net.ipv4.tcp_keepalive_time:保活时间" \ "net.ipv4.tcp_congestion_control:拥塞控制算法" \ "net.ipv4.tcp_slow_start_after_idle:空闲后慢启动" \ "net.ipv4.tcp_no_metrics_save:不保存连接指标" \ "net.ipv4.tcp_mem:TCP内存限制" \ "net.core.netdev_max_backlog:网卡队列" printf "${BOLD}%-26s | %s${NC}\n" "参数" "当前值" printf "${BOLD}%-26s | %s${NC}\n" "--------------------------" "------------------------------" for item in "$@"; do KEY="${item%%:*}" DESC="${item#*:}" VAL=$(read_sysctl "$KEY")printf"%-26s | %s\n""$DESC""$VAL" done# 系统状态 - 使用固定宽度对齐 echo ""printf"${BOLD}${CYAN}%-26s${NC}\n""系统当前状态 (sockstat)"printf"${BOLD}%-26s${NC}\n""--------------------------"# 读取sockstat并格式化输出whileread -r line; doprintf"%-26s | %s\n""""$line" done < /proc/net/sockstat 2>/dev/null | grep -E "^TCP:|^TCP6:" || head -5 /proc/net/sockstat 2>/dev/null# 内存信息 echo ""printf"${BOLD}${CYAN}%-26s${NC}\n""系统内存信息"printf"${BOLD}%-26s${NC}\n""--------------------------"local memtotal=$(awk '/MemTotal/{print $2}' /proc/meminfo 2>/dev/null)local pagesize=$(getconf PAGE_SIZE 2>/dev/null || echo 4096) [ -n "$memtotal" ] && printf"%-26s | %s kB (%s)\n""物理内存""$memtotal""$(hr $((memtotal * 1024)))"printf"%-26s | %s bytes\n""内存页大小(PAGE_SIZE)""$pagesize"# TCP内存计算local tcp_mem=$(read_sysctl "net.ipv4.tcp_mem")if [ "$tcp_mem" != "N/A" ]; thenlocal low=$(echo "$tcp_mem" | awk '{print $1}')local high=$(echo "$tcp_mem" | awk '{print $2}')local max=$(echo "$tcp_mem" | awk '{print $3}')local pages=$(($pagesize / 1024))printf"%-26s | %s pages\n""TCP内存限制""low:$low high:$high max:$max"printf"%-26s | %s kB / %s kB / %s kB\n"" └─ 转换为kB""$((low * pages))""$((high * pages))""$((max * pages))" fi}usage() { cat << 'EOF'TCP内存监控工具用法: ./tcpcheck [选项] [数字] 监控模式,每N秒刷新 -k 仅显示内核参数 -h 显示帮助EOF}case "$1" in -h|--help) usage ;; -k|--kernel) kernel_info ;; [0-9]*) while true; do clear date '+%Y-%m-%d %H:%M:%S' main && kernel_info echo "" printf "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" printf "刷新间隔: %ss | 按 Ctrl+C 退出\n" "$1" printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n" sleep "$1" done ;; *) main && kernel_info ;;esac