从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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/962402.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MFC开发,给对话框添加垂直滚动条并解决鼠标滚动响应的问题

无论在使用QT或者MFC进行界面开发时&#xff0c;都会出现在一个对话框里面存在好多的选项&#xff0c;导致对话框变得非常长或者非常大&#xff0c;就会显现的不美观&#xff0c;在这种情况下通常是添加一个页面的滚动条来解决这个问题&#xff0c;下面我们就来介绍给MFC的对话…

(二)QT——按钮小程序

目录 前言 按钮小程序 1、步骤 2、代码示例 3、多个按钮 ①信号与槽的一对一 ②多对一&#xff08;多个信号连接到同一个槽&#xff09; ③一对多&#xff08;一个信号连接到多个槽&#xff09; 结论 前言 按钮小程序 Qt 按钮程序通常包含 三个核心文件&#xff1a; m…

QT简单实现验证码(字符)

0&#xff09; 运行结果 1&#xff09; 生成随机字符串 Qt主要通过QRandomGenerator类来生成随机数。在此之前的版本中&#xff0c;qrand()函数也常被使用&#xff0c;但从Qt 5.10起&#xff0c;推荐使用更现代化的QRandomGenerator类。 在头文件添加void generateRandomNumb…

受击反馈HitReact、死亡效果Death Dissolve、Floating伤害值Text(末尾附 客户端RPC )

受击反馈HitReact 设置角色受击标签 (GameplayTag基本了解待补充) 角色监听标签并设置移动速度 创建一个受击技能&#xff0c;并应用GE 实现设置角色的受击蒙太奇动画 实现角色受击时播放蒙太奇动画&#xff0c;为了保证通用性&#xff0c;将其设置为一个函数&#xff0c;并…

C++,STL 命名空间:理解 std 的作用、规范与陷阱

文章目录 引言一、为什么需要 std 命名空间&#xff1f;二、std 命名空间的组成三、使用 std 命名空间的正确姿势1. 显式作用域限定2. 谨慎使用 using 声明3. 头文件中禁止 using namespace std 四、常见陷阱与解决方案陷阱 1&#xff1a;与第三方库命名冲突陷阱 2&#xff1a;…

第11章:根据 ShuffleNet V2 迁移学习医学图像分类任务:甲状腺结节检测

目录 1. Shufflenet V2 2. 甲状腺结节检测 2.1 数据集 2.2 训练参数 2.3 训练结果 2.4 可视化网页推理 3. 下载 1. Shufflenet V2 shufflenet v2 论文中提出衡量轻量级网络的性能不能仅仅依靠FLOPs计算量&#xff0c;还应该多方面的考虑&#xff0c;例如MAC(memory acc…

【ArcGIS遇上Python】批量提取多波段影像至单个波段

本案例基于ArcGIS python,将landsat影像的7个波段影像数据,批量提取至单个波段。 相关阅读:【ArcGIS微课1000例】0141:提取多波段影像中的单个波段 文章目录 一、数据准备二、效果比对二、python批处理1. 编写python代码2. 运行代码一、数据准备 实验数据及完整的python位…

HTB:Administrator[WriteUP]

目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 使用nmap对靶机…

vscode+WSL2(ubuntu22.04)+pytorch+conda+cuda+cudnn安装系列

最近在家过年闲的没事&#xff0c;于是研究起深度学习开发工具链的配置和安装&#xff0c;之前欲与天公试比高&#xff0c;尝试在win上用vscodecuda11.6vs2019的cl编译器搭建cuda c编程环境&#xff0c;最后惨败&#xff0c;沦为笑柄&#xff0c;痛定思痛&#xff0c;这次直接和…

亚博microros小车-原生ubuntu支持系列:17 gmapping

前置依赖 先看下亚博官网的介绍 Gmapping简介 gmapping只适用于单帧二维激光点数小于1440的点&#xff0c;如果单帧激光点数大于1440&#xff0c;那么就会出【[mapping-4] process has died】 这样的问题。 Gmapping是基于滤波SLAM框架的常用开源SLAM算法。 Gmapping基于RBp…

FreeRTOS从入门到精通 第十六章(任务通知)

参考教程&#xff1a;【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili 一、任务通知简介 1、概述 &#xff08;1&#xff09;任务通知顾名思义是用来通知任务的&#xff0c;任务控制块中的结构体成员变量ulNotifiedValue就是这个通知值。 &#xff08;2&#…

数据结构选讲 (更新中)

参考 smWCDay7 数据结构选讲2 by yyc 。 可能会补充的&#xff1a; AT_cf17_final_j TreeMST 的 F2 Boruvka算法 目录 AT_cf17_final_j Tree MSTP5280 [ZJOI2019] 线段树 AT_cf17_final_j Tree MST link 题意 给定一棵 n n n 个点的树&#xff0c;点有点权 w i w_i wi​&am…

【01】共识机制

BTF共识 拜占庭将军问题 拜占庭将军问题是一个共识问题 起源 Leslie Lamport在论文《The Byzantine Generals Problem》提出拜占庭将军问题。 核心描述 军中可能有叛徒&#xff0c;却要保证进攻一致&#xff0c;由此引申到计算领域&#xff0c;发展成了一种容错理论。随着…

春晚舞台上的人形机器人:科技与文化的奇妙融合

文章目录 人形机器人Unitree H1的“硬核”实力传统文化与现代科技的创新融合网友热议与文化共鸣未来展望&#xff1a;科技与文化的更多可能结语 2025 年央视春晚的舞台&#xff0c;无疑是全球华人目光聚焦的焦点。就在这个盛大的舞台上&#xff0c;一场名为《秧BOT》的创意融合…

.NET Core缓存

目录 缓存的概念 客户端响应缓存 cache-control 服务器端响应缓存 内存缓存&#xff08;In-memory cache&#xff09; 用法 GetOrCreateAsync 缓存过期时间策略 缓存的过期时间 解决方法&#xff1a; 两种过期时间策略&#xff1a; 绝对过期时间 滑动过期时间 两…

如何从客观角度批判性阅读分析博客

此文仅以个人博客为例&#xff0c;大量阅读朋友反馈给我的交流让我得知他们所理解我的博客所表达的意思并非我所想表达的&#xff0c;差异或大或小&#xff0c;因人而异。 观点与事实 只有从客观角度反复批判性阅读和分析&#xff0c;才能逐渐清晰观点和事实。 观点不等于事实…

【力扣】49.字母异位词分组

AC截图 题目 思路 由于互为字母异位词的两个字符串包含的字母相同&#xff0c;因此对两个字符串分别进行排序之后得到的字符串一定是相同的&#xff0c;故可以将排序之后的字符串作为哈希表的键。 可以遍历strs&#xff0c;将其中每一个str排序&#xff0c;然后用unodered_ma…

【4Day创客实践入门教程】Day4 迈向高手之路——进一步学习!

Day4 迈向高手之路——进一步学习&#xff01; 目录 Day4 迈向高手之路——进一步学习&#xff01;更多的开发板外壳制作 Day0 创想启程——课程与项目预览Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟Day4…

什么是线性化PDF?

线性化PDF是一种特殊的PDF文件组织方式。 总体而言&#xff0c;PDF是一种极为优雅且设计精良的格式。PDF由大量PDF对象构成&#xff0c;这些对象用于创建页面。相关信息存储在一棵二叉树中&#xff0c;该二叉树同时记录文件中每个对象的位置。因此&#xff0c;打开文件时只需加…

向下调整算法(详解)c++

算法流程&#xff1a; 与⽗结点的权值作⽐较&#xff0c;如果⽐它⼤&#xff0c;就与⽗亲交换&#xff1b; 交换完之后&#xff0c;重复 1 操作&#xff0c;直到⽐⽗亲⼩&#xff0c;或者换到根节点的位置 大家可能会有点疑惑&#xff0c;这个是大根堆&#xff0c;22是怎么跑到…