Linux快速定位日志 排查bug技巧和常用命令、系统监控命令

一、快速根据关键字定位错误信息

grep 命令

查找包含关键字的日志内容

在 Linux 系统中,可以使用 grep 命令来查找日志文件中包含特定关键字的行。假设你的日志文件路径为 /var/log/myapp.log,你想要查找包含关键字 "abc" 的日志内容,可以按照以下步骤操作:

如果你很明确要找的内容在某一个文件xxx.log中,可以使用下面两条命令输出内容所在行号:

cat xxx.log |grep -n "xxx"

grep -n "xxx" xxx.log

如果你有大量的日志文件,不确定要找的东西在哪里,可以使用递归搜索,这条命令可以快速找到所有含关键字的行

grep -r -n "xxx" .
  • -r :递归搜索,即搜索当前目录及其子目录中的所有文件。
  • . :表示当前目录。
  • -n:输出行号

这个命令会在当前文件夹及其所有子文件夹中的所有文件内搜索包含“xxxx”这段文字的行,并将结果输出。

找到行号后,通过下一条命令 直接输出当前行号下的日志

在这里插入图片描述
这个命令是用来查看一个日志文件 xxx.log 中特定范围的行。从第 501 行开始,显示接下来的 100 行日志

tail -n +501 xxx.log | head -n 100

这样可以更快速更精准的定位到关键日志,而不是去打开日志文件来搜索,或者二次触发bug,来查看日志,这些命令能够帮助你更高效地查找和分析日志文件中的特定信息。

正则搜索

某个服务的日志文件保存在以 personnel 开头的多个文件夹中,需要查找特定关键字(如异常信息、用户ID、错误码等),可以使用下面这句命令:

find . -type d -name "personnel*" -exec grep -rn "关键字" {} +

这条命令是 Linux 上的 find 命令,用于在指定的目录及其子目录中搜索符合条件的文件夹,并执行指定的操作。以下是这条命令的详细解释:

命令详解

  1. find .
    表示从当前目录(.)开始递归查找。可以替换成指定的路径(如 /path/to/start)。

  2. -type d
    指定查找的文件类型为目录(directory)。

  3. -name "personnel*"
    匹配名称以 personnel 开头的目录。* 是通配符,表示任意字符。

  4. -exec
    指定对找到的目录执行接下来的命令。

  5. grep -rn "关键字" {}
    对找到的目录使用 grep 命令进行关键字搜索,find 查找到的目录名会替换 {}

  6. +
    表示将所有匹配的目录作为参数一起传递给 grep,而不是对每个目录分别执行一次。这种方式通常比 \; 更高效。


如果你希望从当前目录开始递归查找所有名字以 personnel 开头的文件,并在这些文件中搜索特定的关键词,可以使用以下命令:

find . -type f -name "personnel*" -exec grep -rn "关键词" {} +

二、动态实时查看日志

tail 命令

tail -f xxx.log实时展示日志末尾内容,默认最后10行,相当于增加参数 -n 10

tail -f server.log

查看日志正数20行内容

tail -n +20 xxx.log

cat 命令

cat 区别于tail是对日志进行全文搜索,其中-n的作用是显示行号

cat -n xxx.log | grep "xxx"

-C 选项来显示检索结果的前后几行,-A 选项展示检索结果后几行,-B选项展示检索结果前几行

cat -n xxx.log | grep -C 5 'xxx'

less 命令

less 命令多用于读取文本文件,也可用于读取实时被更改的文件。ctrl +c 中断实时读取显示,按 q 会退出less视图,选项 +F 可以实时跟踪文件的更改:

less +F xxx.log

第一步:打开日志文件

less xxx.log

第二步:定位到日志文件的最后一行:

shift+g 移动到最后一行

第三步:往前一页一页翻页查看

ctrl+b 

1.全屏导航

ctrl + F - 向前移动一屏
ctrl + B - 向后移动一屏
ctrl + D - 向前移动半屏
ctrl + U - 向后移动半屏

vim编辑模式

进入编辑日志文档

vim xxx.log

正向查找,配合n键可以将光标移动到下一个符合条件的地方

/关键字   

反向查找,配合shift + n 键可以将光标移动到下一个符合条件的地方

?关键字 

三、 常用监控命令

1. free 命令

free 命令是Linux系统中用于显示内存使用情况的一个常用工具。它提供了关于系统内存使用的详细信息,包括物理内存(RAM)和虚拟内存。当你在终端中运行 free 命令时,它会显示几个与内存使用相关的值。以下是这些值的含义:

  • total:表示系统中物理内存(RAM)的总量,单位可以是千字节(KB)、兆字节(MB)或吉字节(GB)。
  • used:显示当前正在被各种进程和操作系统本身使用的物理内存量。
  • free:表示当前未被使用的物理内存量。
  • shared:表示多个进程共享的内存量。
  • buffers:显示用于缓冲磁盘I/O操作的内存量。
  • cache:表示用于缓存从磁盘或其他存储设备频繁访问的数据的内存量。
  • available:表示估计的可用内存量,用于新进程分配。它考虑到了用于缓冲和缓存的内存,如果需要,可以被其他应用程序释放。

常用参数:

  • -b 以Byte为单位显示内存使用情况。
  • -k 以KB为单位显示内存使用情况。
  • -m以MB为单位显示内存使用情况。
  • -h 以比较人性化的方式显示内存使用情况。
  • -o 不显示缓冲区调节列。
  • -s <间隔秒数> 持续观察内存使用状况。
  • -t 显示内存总和列。
  • -V 显示版本信息

free 命令中的信息都来自于 /proc/meminfo 文件。/proc/meminfo 文件包含了更多更原始的信息

2.top命令

实时监控系统的运行状态,并且可以按照cpu及内存等进行排序

top 命令是 Linux 和其他类 Unix 系统上常用的实时系统监控工具,它提供了一个动态的、交互式的实时视图,显示系统的整体性能信息以及正在运行的进程的相关信息。这个命令是系统管理员最重要的工具之一,被广泛用于监视服务器的负载。top 命令是一个交互命令,在运行 top 的时候还可以运行很多命令。

命令行选项

  • -d <秒数>:指定top命令的刷新时间间隔,单位为秒。
  • -n <次数>:指定top命令运行的次数后自动退出。
  • -p <进程ID>:仅显示指定进程ID的信息。
  • -u <用户名>:仅显示指定用户名的进程信息。
  • -H:在进程信息中显示线程详细信息。
  • -i:不显示闲置(idle)或无用的进程。
  • -b:以批处理(batch)模式运行,直接将结果输出到文件。
  • -c:显示完整的命令行而不截断。
  • -S:累计显示进程的CPU使用时间。

显示信息

总体系统信息:包括系统的运行时间和平均负载、当前运行的进程和线程数目、总体CPU使用率和各个核心的使用情况、总体内存使用情况、可用内存和缓存。

进程信息:包括进程的标识符、运行进程的用户名、进程的优先级、进程的优先级调整值、进程使用的虚拟内存大小、进程实际使用的物理内存大小、进程共享的内存大小、进程占用CPU的使用率、进程占用内存的使用率、进程的累计CPU时间。

实际实例分析

下面是在一台机器上跑了 top 之后得到的信息,我们来分析一下

top - 09:45:49 up 166 days, 30 min,  5 users,  load average: 39.40, 103.11, 159.44
Tasks: 274 total,   2 running, 272 sleeping,   0 stopped,   0 zombie
%Cpu(s): 12.1 us, 44.8 sy,  0.0 ni,  0.0 id, 43.0 wa,  0.0 hi,  0.0 si,  0.0 st 
MiB Mem :  31947.6 total,    196.5 free,  31877.2 used,    352.2 buff/cache     
MiB Swap:    976.0 total,      0.0 free,    976.0 used.     70.4 avail Mem 

从你提供的 top 命令输出来看,系统存在严重的性能问题,主要表现为 IO 瓶颈 和 内存耗尽,具体分析如下:
1. 系统负载(load average)异常高

load average: 39.40, 103.11, 159.44

这三个数值分别代表系统过去 1 分钟、5 分钟、15 分钟的平均负载。

正常情况下,负载值应接近或小于 CPU 核心数(例如 8 核 CPU 负载应在 8 左右)。而当前数值(尤其是 15 分钟均值 159.44)远高于正常范围,说明系统长期处于超负荷状态。
结合其他指标,这种高负载主要由 IO 等待 引起(而非 CPU 计算密集)。

2. CPU 资源被 IO 等待严重占用

%Cpu(s): 12.1 us, 44.8 sy,  0.0 ni,  0.0 id, 43.0 wa, ...
  • us(用户态 CPU):12.1%,正常范围。
  • sy(内核态 CPU):44.8%,偏高,可能是内核在处理大量 IO 请求。
  • wa(IO 等待):43.0%,非常高!表示 CPU 有 43% 的时间在等待磁盘 IO 操作完成,是系统卡顿的核心原因。
  • id(空闲 CPU):0.0%,CPU 完全没有空闲,资源耗尽。

3. 内存和交换空间(swap)耗尽

MiB Mem :  31947.6 total,    196.5 free,  31877.2 used,    352.2 buff/cache     
MiB Swap:    976.0 total,      0.0 free,    976.0 used.     70.4 avail Mem 
  • 物理内存(Mem):总内存 32GB,已使用 31.8GB,仅剩 196MB 空闲,几乎耗尽。
  • 交换空间(Swap):总大小 976MB,已完全用尽(0 空闲)。
  • avail Mem 仅 70.4MB:系统可立即分配的内存极少,内存严重不足。

综合结论:系统因内存耗尽导致严重 IO 阻塞

  1. 内存枯竭:物理内存和 swap 完全用尽,系统被迫频繁进行内存页面交换(swap in/out)。
  2. IO 风暴:内存交换依赖磁盘 IO,导致 kswapd0 进程(内存交换守护进程)频繁读写磁盘,引发极高的 IO 负载(wa 43%)。
  3. 恶性循环:IO 阻塞导致 CPU 等待,系统响应变慢,进而加剧任务堆积,使负载持续升高。
    紧急处理建议

当前系统已处于严重过载状态,可能出现响应迟缓、服务中断等问题,建议优先处理内存和 IO 瓶颈。

kswapd0Linux 内核中的一个内核线程(kernel thread),专门负责 内存页面回收(memory
reclaim)
的。 简单来说,它的作用就是: 👉 当系统内存不足时,kswapd0
会在后台自动工作,释放内存、回收页面,以防止系统因为内存耗尽而卡死。

kswapd0 在以下情况会变得非常活跃:

  • 系统内存紧张(可用内存低于阈值)
  • 程序占用大量内存(例如 Java、数据库)
  • 文件缓存(page cache)占用太多内存
  • 存在内存泄漏

四、线上出现 OOM(OutOfMemoryError)

🚀 2. 查看系统日志,确认 OOM 类型(最重要)

线上发生 OOM 时,进程往往已经不可用或即将挂掉,第一时间要拿到堆转储文件(Heap Dump)

  1. 自动触发(最推荐):确保启动参数配置了:
    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump/
    这样 OOM 发生时会自动生成 .hprof 文件。
  2. 手动捕获:如果进程还没死,使用 jmap 立即导出:
    jmap -dump:format=b,file=heap.hprof <pid>
  3. 日志收集:保存当时的 GC 日志业务日志以及系统的 OOM Killer 日志/var/log/messages),确认是 JVM 内存溢出还是被操作系统由于物理内存不足直接杀掉。

第二步:初步定位(分析错误类型)

java.lang.OutOfMemoryError: Java heap space

通过异常信息明确是哪块内存区域出了问题:

错误信息常见成因排查方向
Java heap space堆内存不足内存泄漏(Leak)或内存溢出(Overflow,如大对象)
GC overhead limit exceededGC 回收效率极低循环创建对象或内存几乎被占满,频繁 Full GC
Metaspace元空间不足动态生成类过多(如 Spring CGLIB, Groovy)
Unable to create new native thread无法创建线程线程泄漏、线程池设置不合理或操作系统限制
Direct buffer memory直接内存不足NIO、Netty 使用不当,未手动释放堆外内存

再看堆栈:是谁触发的 OOM(定位入口)

看 OOM 后面那段 at xxx() 的堆栈。

示例(Heap OOM),盯第一个你自己的业务代码

java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3332)
    at java.util.ArrayList.grow(ArrayList.java:237)
    at java.util.ArrayList.add(ArrayList.java:458)
    at com.xxx.service.OrderService.buildOrderList(OrderService.java:126)


结合“触发动作”理解异常

不同 OOM,堆栈含义不同。

1️⃣ Java heap space:说明:集合无限增长或一次性加载大数据
2️⃣ GC overhead limit exceeded:不是这行代码错而是 在执行它时,堆已经快没了,对象一直被引用,GC 不敢回收
3️⃣ Metaspace:CGLIB / 动态代理疯狂生成类


第三步:深度分析(离线离场)

日志只能告诉你「发生了什么类型的 OOM」,而 Heap Dump 才能告诉你「是谁把内存吃光的」。

将生成的 .hprof 文件下载到本地,使用专业工具进行分析:

  1. MAT (Memory Analyzer Tool)
    • Leak Suspects 报告:自动分析可能的泄漏点。
    • Histogram(直方图):看哪些类产生的实例最多、占用空间最大。
    • Dominator Tree(支配树):查看对象的引用链,找出是谁持有了这些大对象。

第四步:典型案例对号入座

  • 内存泄漏:某个集合类(如 HashMap)作为静态变量,只增不减,导致对象无法被 GC 回收。
  • 大对象入堆:SQL 查询没加 limit 一次查出百万数据,或解析巨大的 XML/JSON 文件。
  • 代码死循环:循环内不断 new 对象,导致瞬间填满堆空间。
  • 资源未关闭:文件流、数据库连接或网络连接未在 finally 中关闭。

第五步:解决方案

  1. 代码层面:修复内存泄漏,优化算法,增加 limit 限制,使用流式处理代替一次性加载。
  2. 参数层面
  • 增加堆内存:-Xmx, -Xms
  • 调整元空间:-XX:MaxMetaspaceSize
  • 更换垃圾回收器:如使用 G1 或 ZGC 获得更好的大内存管理能力。
  1. 架构层面:引入限流降级,防止瞬时大流量压垮内存。

五、线上出现CPU过载

1. 定位占用 CPU 的进程

top 

使用 top 找到 CPU 占用最高的 PID,假设是 12345

2.进一步查看线程级别(找出哪条线程在“烧 CPU”)

top -Hp 12345

这会显示该进程内所有线程的 CPU 占用情况。

  • 按 P:按 CPU 排序
  • 找到一个 CPU 高的线程号,例如 56789

把它转成十六进制:

printf "%x\n" 56789

假设结果是 0xdd85

3. 结合 Java分析

如果是 Java 应用(如 Spring Boot),用以下命令导出线程堆栈:

jstack 12345 | grep -A 50 dd85

然后你就能看到是哪段代码在占用 CPU —— 比如一个死循环、频繁的日志输出、线程池爆炸等。

这个命令是 Java 线上定位线程问题的经典组合,一句话解释就是:

在 Java 线程堆栈中,精准找到 Linux 线程 ID 为 dd85 的那个线程在跑什么代码

下面我把它逐段拆开解释,看完你就能自己用了。

  • Java 进程的所有线程堆栈
  • 找到 nid = 0xdd85 的线程
  • -A :是After的意思,把它下面的 20 行堆栈信息一起打印出来

六、JPS命令

很好,这个问题问得很实用!
jpsJDK 自带的一个命令行工具,全名叫:

Java Virtual Machine Process Status Tool

它的作用就是:

列出当前机器上所有正在运行的 Java 进程(JVM),以及它们对应的主类(Main Class)。

七、频繁FullGC问题如何排查

一、先确认:是不是真的“频繁 Full GC”

1️⃣看 GC 日志(最关键)

日志里找:Full GC、Pause Full, 如果只是频繁 Young GC,不是这个问题。

-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/logs/gc.log

GC 实时频率

jstat -gc <pid> 1s 10

重点看这几列:

含义危险信号
FGCTFull GC 总耗时持续上涨
FGCFull GC 次数每分钟多次
OUOld 区使用量接近 OC
OCOld 区容量接近上限

👉 判断标准(经验值)

  • Full GC > 1 次 / 分钟:已经异常
  • 连续 Full GC:基本要 OOM 了

二、判断 Full GC 的“类型”(非常关键)

你要知道 JVM 为什么触发 Full GC。

2️⃣ 看 GC 日志(核心)

常见触发原因:

① Allocation Failure

👉 老年代满了


② Metadata GC Threshold

👉 Metaspace 不够


③ System.gc()

👉 代码或三方库主动调用


④ Promotion Failed

👉 年轻代对象晋升老年代失败


三、按类型对症排查(重点)

场景一:老年代满(最常见)

表现

  • OU ≈ OC
  • Full GC 后 Old 几乎不降

排查步骤

1️⃣ dump 堆(必须)
jmap -dump:live,format=b,file=heap.hprof <pid>
2️⃣ 用 MAT 看

重点:

  • Dominator Tree
  • Retained Size 最大的对象

常见“元凶”:

对象原因
HashMap / ConcurrentHashMap本地缓存泄漏
ArrayList一次性查全量
byte[]文件 / IO
StringJSON / 拼接
ThreadLocalMapThreadLocal 泄漏

场景二:Metaspace 导致 Full GC

表现

Full GC (Metadata GC Threshold)

原因

  • CGLIB / 动态代理
  • 频繁创建类
  • 热加载

排查

jcmd <pid> VM.metaspace

解决

-XX:MaxMetaspaceSize=512m
  • 减少动态代理

场景三:System.gc() 触发 Full GC(非常隐蔽)

排查

jmap -histo <pid> | grep System

或者:

jcmd <pid> VM.flags

解决

-XX:+DisableExplicitGC

场景四:年轻代晋升失败(Promotion Failed)

表现

  • Minor GC 后 Old 突然暴涨
  • Full GC 非常频繁

原因

  • 年轻代太小
  • 大对象直接进老年代

解决

-Xmn 调大年轻代
-XX:PretenureSizeThreshold

四、最常见 5 个根因(经验总结)

排名原因
1缓存无上限
2批量操作不分页
3ThreadLocal 泄漏
4大对象(导出 / 文件)
5JVM 堆太小

频繁 Full GC ≠ GC 参数问题,而是“老年代被塞满了”

Jstat

jstat线上排查 GC / 内存问题最常用、最安全的 JVM 命令之一,几乎不影响业务。下面我给你一份 工程师实战版 jstat 速查 + 解读

一、jstat 是干什么的?

一句话:

实时查看 JVM 各内存区域使用情况和 GC 行为

适合:

  • 频繁 Full GC
  • OOM 排查
  • 内存是否回收
  • GC 是否异常

二、最常用的 3 个 jstat 命令(必会)

1️⃣ jstat -gc(最常用)

jstat -gc <pid> 1s 10

含义:

  • 每 1 秒打印一次
  • 共打印 10 次
输出示例
 S0C    S1C    S0U    S1U      EC       EU        OC        OU       MC     MU    CCSC   CCSU   YGC   YGCT   FGC  FGCT   GCT
1024.0 1024.0  0.0   512.0  8192.0   2048.0   16384.0   15800.0   2048.0 1900.0  256.0  230.0   320   12.34   15  98.76  111.1
重点字段解释(一定要会)
字段含义排查重点
EC / EUEden 容量 / 使用对象创建是否快
OC / OUOld 容量 / 使用是否快满
YGCYoung GC 次数是否过于频繁
FGCFull GC 次数核心指标
FGCTFull GC 总耗时是否拖垮服务

👉 OU 接近 OC + FGC 不断涨 = 危险


2️⃣ jstat -gcutil(看百分比,更直观)

jstat -gcutil <pid> 1s

输出示例:

 S0     S1     E      O      M     CCS   YGC   YGCT   FGC   FGCT   GCT
 0.00  78.23  25.41  96.12  91.33  89.10  320   12.34   15   98.76  111.1

重点:

  • O > 90%:老年代几乎满
  • FGC 不断增长:Full GC 风暴

👉 推荐:新人先看 gcutil


3️⃣ jstat -gccause(看 GC 原因)

jstat -gccause <pid> 1s

示例:

 LGCC                 GCC
 Allocation Failure   Allocation Failure

常见原因:

原因含义
Allocation Failure内存不够
Metadata GC ThresholdMetaspace
System.gc()主动 GC
Promotion Failed晋升失败

👉 定位 Full GC 原因非常关键

jps

因为在一台机器上,可能同时跑很多个 Java 服务,比如:

  • salary-boot.jar
  • report-boot.jar
  • nginx (不是 Java)
  • mysql (也不是 Java)

ps -ef | grep java 虽然也能查到 Java,但没有专门针对 JVM。

jps 专门用来找 JVM:

  • 它只列出 Java 进程
  • 能直接显示出 主类名jar 包名

🔍 最常用命令示例

jps -l

输出:

12345 com.dekeinfo.personnel.ApplicationMain
23456 org.springframework.boot.loader.JarLauncher
34567 sun.tools.jps.Jps
  • 12345 是进程号(PID)
  • com.dekeinfo.personnel.ApplicationMain 是启动类(如果是 Spring Boot 就是你的 main() 类)
  • JarLauncher 则表示用 spring-boot-loader 启动的 jar

这样就可以很快看出:
✅ 哪些 Java 应用正在跑
✅ 分别对应哪个类


🛠 常用选项

命令说明
jps列出所有 Java 进程 PID
jps -l列出全类名(包名+类名)或 jar 的全路径
jps -v显示 JVM 启动参数(如 -Xmx
jps -m显示传给主类的参数(main(String[] args)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值