从0开始,来看看怎么去linux排查Java程序故障

一,前提准备

最基本前提:你需要有liunx环境,如果没有请参考其它文献在自己得到local建立一个虚拟机去进行测试。

有了虚拟机之后,你还需要安装jdk和配置环境变量

1. 安装JDK(以OpenJDK 17为例)

下载JDK

# 进入用户主目录
cd ~

# 下载OpenJDK 17(以.tar.gz包为例)
wget https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-x64_bin.tar.gz

# 或Oracle JDK(需官网同意许可协议)
# wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz

 

这里就已经下好了 

 解压并安装

# 创建安装目录(需sudo权限)
sudo mkdir -p /usr/local/java

# 解压JDK到目标目录
sudo tar -xzvf openjdk-17.0.2_linux-x64_bin.tar.gz -C /usr/local/java

# 查看解压后的目录名(例如jdk-17.0.2)
ls /usr/local/java

命令解释

mkdir -p /path/to/directory
  • 递归创建目录:当你指定的路径中某些目录不存在时,mkdir -p 会自动创建这些缺失的父目录。
  • 不会报错:如果目录已经存在,mkdir -p 不会报错,命令会正常执行。
tar -xzvf openjdk-17.0.2_linux-x64_bin.tar.gz -C /usr/local/java

tar -xzvf 是用来解压 .tar.gz.tgz 文件的命令。

  • x:表示 解压(extract)。
  • z:表示 通过 gzip 压缩格式进行解压(unzip the gzip file)。
  • v:表示 显示详细信息,在解压时列出文件名。这个选项是可选的,用来查看解压过程中有哪些文件被处理。
  • f:表示 指定文件,后面需要跟要解压的 .tar.gz 文件名。

2, 配置环境变量

编辑环境变量文件

# 打开用户环境变量配置文件(以bash为例)
nano ~/.bashrc  # 或 ~/.bash_profile、~/.zshrc(根据Shell类型)

命令解释

  • nano:是一个命令行下的文本编辑器。它非常简单,适合快速编辑文件。
  • ~/.bashrc:是当前用户主目录下的 Bash 配置文件。每当你打开一个新的终端时,Bash shell 会加载该文件。在这个文件中,你可以设置环境变量、命令别名、shell 提示符样式等。

添加以下内容到文件末尾

需要注意,不能有空格 

# 手动安装配置
export JAVA_HOME=/usr/local/java/jdk-17.0.2  # 替换为实际解压路径
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

# 包管理器安装配置(若使用方式2)
# export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
# export PATH=$JAVA_HOME/bin:$PATH

 

使配置生效 

source ~/.bashrc  # 根据实际配置文件选择

 验证安装

# 检查Java版本
java -version

# 输出应类似:
openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode)

# 检查JAVA_HOME
echo $JAVA_HOME
# 输出:/usr/local/java/jdk-17.0.2

 

 自动化脚本安装示例:

#!/bin/bash
# 一键安装并配置JDK 17(手动方式)
JDK_URL="https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-x64_bin.tar.gz"
INSTALL_DIR="/usr/local/java"

# 下载并解压
sudo mkdir -p $INSTALL_DIR
wget $JDK_URL -O /tmp/jdk17.tar.gz
sudo tar -xzvf /tmp/jdk17.tar.gz -C $INSTALL_DIR

# 配置环境变量
echo "export JAVA_HOME=$INSTALL_DIR/$(ls $INSTALL_DIR)" >> ~/.bashrc
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

# 验证
java -version

 二,Java代码准备

编写一个简单的让程序不断创建新对象,然后GC在不停地回收,但是又回收不掉地样例。并打包为jar包给到我们的liunx服务器。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class Main {
    // 内存泄漏:让对象无法被GC回收
    private static final List<byte[]> LEAK_LIST = new ArrayList<>();

    // CPU密集型任务开关
    private static final AtomicBoolean RUNNING = new AtomicBoolean(true);

    public static void main(String[] args) {
        // 内存泄漏线程:持续分配内存,触发频繁GC
        new Thread(() -> {
            while (true) {
                // 每次分配1MB内存(不会被回收)
                LEAK_LIST.add(new byte[1024 * 1024]);
                try {
                    Thread.sleep(100); // 控制内存分配速度
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "MemoryLeakThread").start();

        // CPU密集型线程:死循环计算,占用CPU
        new Thread(() -> {
            while (RUNNING.get()) {
                // 无意义但耗CPU的计算
                double result = 0;
                for (int i = 0; i < 100000; i++) {
                    result += Math.sin(i) * Math.cos(i);
                }
            }
        }, "CpuIntensiveThread").start();
    }
}

打包为可执行jar包

将jar包给到linux

这里我用的vmware的文件共享区进行的共享的。

在虚拟机的设置里面

在选项这里进行配置一下

vmware的文件共享区在Linux中的/mnt/hgfs/ 文件下

 如果/mnt/hgfs 目录为空

  • 可能原因

    • VMware Tools未正确安装。

    • 共享文件夹未启用或配置错误。

    • 自动挂载服务未运行。

解决方案
步骤1:检查VMware Tools状态

# 查看服务是否运行(Ubuntu/Debian)
systemctl status vmware-tools.service

# 重启服务(如果未运行)
sudo systemctl restart vmware-tools.service

如果未安装 VMware Tools则

# 检查 open-vm-tools 状态

systemctl status open-vm-tools

# 若服务存在且未运行,

启动服务

sudo systemctl start open-vm-tools

sudo systemctl enable open-vm-tools

步骤2:手动挂载共享文件夹(临时生效)

# 创建挂载点(若目录不存在)
sudo mkdir -p /mnt/hgfs

# 手动挂载
sudo vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other

#如果因为权限不足,可以加权限

sudo usermod -aG root rojer(rojer是用户名)

步骤3:配置开机自动挂载(永久生效)

# 编辑/etc/fstab文件
sudo nano /etc/fstab

# 添加以下行(保存退出)
.host:/    /mnt/hgfs    fuse.vmhgfs-fuse    allow_other,defaults    0    0

# 重新挂载
sudo mount -a

 准备调试工具

使用阿里的arthas

arthas/README_CN.md at master · alibaba/arthas · GitHub

 下载 Arthas 的 arthas-boot.jar 文件

 curl -O https://arthas.aliyun.com/arthas-boot.jar

 

三,开始测试

使用以下JVM参数启动程序,加速问题暴露(JDK1.8版本):
java -Xms100m -Xmx100m        # 限制堆内存为100MB,加速GC触发
 -XX:+UseG1GC                # 使用G1垃圾回收器(观察GC日志)
 -XX:+PrintGCDetails         # 打印GC详细信息
 -XX:+PrintGCDateStamps      # 显示GC时间戳

 -jar
 GcDemo.jar

Java 9 及以上改用 -Xlog:gc

java -Xms100m -Xmx100m -XX:+UseG1GC -Xlog:gc -jar GCdemo.jar

启动之后问题出现

现象验证方法

观察GC频繁:

1,使用ps -ef | grep java

找到java进程的pid

 

2,通过top命令观察java进程的实时状态

2,使用 jstat -gc <pid> 1000(每秒刷新):

观察GC回收状况,从上面命令可以看出内存资源并不紧张,所以这里只做展示

YGC(Young GC次数)和 FGC(Full GC次数)会快速上升。

从上面可以看出fullGC的次数才3次,且回收时间不大,说明内存情况很健康。又从top中看到cpu资源已经打满,说明有程序在疯狂占用cpu的计算资源。

这里解释一下上图的代表意思

字段说明
S0CSurvivor Space 0 Capacity(幸存区 0 容量),表示幸存区 0 的容量。
S1CSurvivor Space 1 Capacity(幸存区 1 容量),表示幸存区 1 的容量。
S0USurvivor Space 0 Utilization(幸存区 0 使用量),表示幸存区 0 当前使用的内存量。
S1USurvivor Space 1 Utilization(幸存区 1 使用量),表示幸存区 1 当前使用的内存量。
ECEden Space Capacity(伊甸园区容量),表示伊甸园区的容量。
EUEden Space Utilization(伊甸园区使用量),表示伊甸园区当前的使用量。
OCOld Generation Capacity(老年代容量),表示老年代的容量。
OUOld Generation Utilization(老年代使用量),表示老年代当前使用的内存量。
MCMetaspace Capacity(元空间容量),表示元空间的容量。
MUMetaspace Utilization(元空间使用量),表示元空间当前使用的内存量。
CCSCCompressed Class Space Capacity(压缩类空间容量),表示压缩类空间的容量。
CCSUCompressed Class Space Utilization(压缩类空间使用量),表示压缩类空间的当前使用量。
YGCYoung Generation GC Count(年轻代垃圾回收次数),表示年轻代的垃圾回收次数(包括 Minor GC)。
YGCTYoung Generation GC Time(年轻代垃圾回收时间),表示年轻代垃圾回收所花费的时间(单位:秒)。
FGCFull GC Count(Full GC 次数),表示 Full GC(完全垃圾回收)发生的次数。
FGCTFull GC Time(Full GC 时间),表示 Full GC 所花费的时间(单位:秒)。
CGCConcurrent GC Count(并发 GC 次数),表示并发垃圾回收的次数。
CGCTConcurrent GC Time(并发 GC 时间),表示并发垃圾回收的总时间。
GCTTotal GC Time(总垃圾回收时间),表示自启动以来的所有垃圾回收时间(单位:秒)。

详细观察cpu的占用情况

top -p <pid>

然后 按 H(大写的 H)切换到线程视图:

  • 按下 H 键后,top 会从显示进程列表切换到显示线程列表,每个线程会显示为一个单独的条目。

 使用Arthas诊断:

# 1. 启动Arthas
java -jar arthas-boot.jar

这里选择所要监控的程序。

需要注意,如果出现连接异常,且

~/logs/arthas/arthas.log

路径下log中有

Arthas server agent start...

java.lang.OutOfMemoryError: Java heap space

说明你当前的机器在不断消耗内存,导致arthas起不起来!

因为在jvm初始化的时候,这个阶段非常吃内存。

 查看线程CPU占用

# 当前系统的实时数据面板,按 ctrl+c 退出。

dashboard

这里可以看出cpu已经打满,但是堆内存情况良好。

 追踪高cpu线程

thread

参数名称参数说明
id线程 id
[n:]指定最忙的前 N 个线程并打印堆栈
[b]找出当前阻塞其他线程的线程
[i <value>]指定 cpu 使用率统计的采样间隔,单位为毫秒,默认值为 200
[--all]显示所有匹配的线程

 

 这里就已经能定位到问题了。我这个样例比较简单,就一个main类。大家可以构建复杂一点的项目,进行一点点调试看问题。

使用java原生的也能定位到问题。可能比较繁琐一点。

使用 jstack 获取线程堆栈信息

使用 jvisualvm 进行图形化分析

等等。

其它arthas常用方法

  • trace:追踪方法调用的堆栈,帮助你查看方法内部的执行情况。
  • monitor:监控方法的执行,特别是性能问题,像慢方法。
  • stack:查看线程堆栈,特别是线程阻塞和死锁问题。
  • watch:监控方法调用,查看参数和返回值,帮助定位参数错误。
  • heapdump:生成堆转储文件,帮助分析内存问题。
  • jstack:查看 Java 进程的堆栈信息,诊断崩溃或线程死锁。

参考官方文档使用说明!

auth | arthas

<think>好的,用户想了解Linux系统故障排查的方法和常用工具。首先,我需要回顾一下已有的引用内容,看看里面有哪些相关的信息。引用[1]提到了几个常见的故障排查方法,比如使用救援模式,理解引导过程。引用[2]讨论的是应用程序故障排查的另类方法,可能涉及工具的使用。引用[3]、[4]、[5]主要涉及网络和系统工具,如lsof、GC查看工具等。 用户的问题包括方法和工具,所以需要把这两部分分开整理。方法方面,可能需要分步骤,比如启动故障、系统性能、网络问题、应用程序问题等。工具方面,需要列出常用的命令和它们的用途,比如strace、dmesg、lsof、top等。要注意每个工具对应的引用来源,正确标注引用标识。 接下来需要确认这些工具是否在引用中有提到。例如,lsof在引用[3]和[5]中都有提到,用于查看文件描述符和socket。strace在引用[2]中可能涉及应用程序调试。dmesg可能和引用[1]的引导过程相关。另外,GC工具在引用[4]中提到,可能与Java应用有关。 需要组织内容结构,先讲方法,再讲工具,每个部分用清晰的标题。方法部分需要按故障类型分类,给出解决步骤。工具部分需要列举工具名称、用途、示例命令,并注明引用来源。确保每个引用标识正确对应,例如救援模式对应引用[1],lsof对应引用[3]和[5]等。 另外,用户可能对某些工具的具体使用感兴趣,可能需要生成相关问题,比如如何分析系统日志,如何追踪进程调用等。要确保生成的问题与内容相关,帮助用户进一步学习。 最后检查是否有遗漏的重要工具或方法,比如网络故障排查中的ping、traceroute,是否在引用中提到。引用[3]提到了网络故障排查命令,所以需要包含这些工具。同时,系统性能工具如top、vmstat、iostat,在引用中可能没有直接提到,但属于常见工具,可以补充,但可能需要确认是否在引用中有相关内容。如果没有,可能需要避免引入未提及的工具,但根据常识,这些是基础工具,应该合理包含。 总结下来,结构大致如下: 1. 故障排查方法: - 启动故障:救援模式(引用1) - 系统性能:top、vmstat(引用4可能涉及GC工具) - 网络问题:ping、tcpdump(引用3、5) - 应用程序:strace、日志分析(引用2) 2. 常用工具: - 系统日志:dmesg(引用1?不确定,可能需要关联) - 进程跟踪:strace(引用2) - 文件/网络:lsof(引用3、5) - 性能监控:top、vmstat、iostat(引用4?) 需要确保每个工具和方法都有对应的引用支持,或者属于常识范围。例如,救援模式明确在引用1中,可以标注。其他工具如strace可能在引用2中提到的应用程序故障排查方法中使用。 最终,回答需要结构清晰,分点列出,正确引用,并生成相关问题。</think>### Linux 系统故障排查方法与常用工具 #### 一、故障排查方法 1. **启动故障排查** - 若系统无法进入单用户模式或出现引导问题,可使用 **Linux 救援模式**(通过安装盘或Live CD启动)修复引导文件或检查文件系统[^1]。 - 分析启动日志: ```bash journalctl -b # 查看本次启动日志 dmesg # 显示内核环形缓冲区中的硬件/驱动信息 ``` 2. **系统性能问题排查** - 使用 `top` 或 `htop` 监控实时进程状态,识别高 CPU/内存占用的进程。 - 通过 `vmstat` 或 `iostat` 分析内存、磁盘 I/O 使用情况。 - 若涉及 Java 应用,使用 `jstat` 或 `jmap` 查看垃圾回收(GC)详情和堆内存分配[^4]。 3. **网络故障排查** - 基础检查: ```bash ping <IP> # 测试连通性 traceroute <IP> # 追踪路由路径 ss -tuln 或 netstat # 查看端口监听状态[^3] ``` - 使用 `tcpdump` 抓包分析流量异常,或 `nmap` 扫描端口开放情况。 4. **应用程序故障排查** - 通过 `strace` 追踪进程的系统调用和信号: ```bash strace -p <PID> # 监控运行中进程的调用 ``` - 结合 `lsof` 查看进程打开的文件描述符(包括网络连接)[^5]。 --- #### 二、常用工具清单 | 工具 | 用途 | 示例命令 | |--------------|-----------------------------------|------------------------------| | **dmesg** | 查看内核日志和硬件错误 | `dmesg | grep error` | | **strace** | 追踪进程的系统调用 | `strace -e open java Main` | | **lsof** | 列出进程打开的文件/网络连接 | `lsof -i :80`[^5] | | **tcpdump** | 抓取网络包分析协议问题 | `tcpdump -i eth0 port 443` | | **jstack** | 生成 Java 线程快照(排查死锁/阻塞) | `jstack <PID> > thread.log` | | **perf** | 分析 CPU 性能瓶颈(如缓存命中率) | `perf record -g <command>` | --- #### 三、典型排查流程 1. **定位问题范围** - 检查系统日志 `/var/log/messages` 或 `journalctl`。 - 使用 `top` 确认资源瓶颈是否由特定进程引起。 2. **深入分析** - 对异常进程使用 `strace` 或 `gdb` 跟踪调用链。 - 若网络超时,结合 `tcpdump` 和 Wireshark 可视化分析。 3. **修复验证** - 修改配置后重启服务(如 `systemctl restart <service>`)。 - 通过压力测试工具(如 `ab` 或 `wrk`)验证稳定性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值