当前位置: 首页 > news >正文

第2章:用户界面与基本监控

1. VisualVM 用户界面概览

1.1 主界面布局

┌─────────────────────────────────────────────────────────────────────────────┐
│  菜单栏 (Menu Bar)                                                          │
├─────────────────────────────────────────────────────────────────────────────┤
│  工具栏 (Toolbar)                                                          │
├─────────────────┬───────────────────────────────────────────────────────────┤
│                 │                                                         │
│   应用程序树     │                                                         │
│  (Applications  │                主视图区域                                │
│     Tree)       │              (Main View Area)                          │
│                 │                                                         │
│  ┌─────────────┐│  ┌─────────────────────────────────────────────────────┐ │
│  │   Local     ││  │                                                     │ │
│  │  ├─ PID 1234││  │              监控/分析视图                           │ │
│  │  ├─ PID 5678││  │           (Monitoring/Profiling Views)              │ │
│  │  └─ PID 9012││  │                                                     │ │
│  │             ││  │                                                     │ │
│  │   Remote    ││  │                                                     │ │
│  │  └─ server1 ││  │                                                     │ │
│  │             ││  │                                                     │ │
│  │  Snapshots  ││  │                                                     │ │
│  │  ├─ heap1   ││  │                                                     │ │
│  │  └─ thread1 ││  │                                                     │ │
│  └─────────────┘│  └─────────────────────────────────────────────────────┘ │
├─────────────────┴───────────────────────────────────────────────────────────┤
│  状态栏 (Status Bar)                                                       │
└─────────────────────────────────────────────────────────────────────────────┘

1.2 界面组件详解

1.2.1 菜单栏 (Menu Bar)

File 菜单

  • Load:加载快照文件
  • Export:导出数据
  • Exit:退出应用程序

Edit 菜单

  • Find:查找功能
  • Copy:复制数据
  • Select All:全选

View 菜单

  • Applications Window:显示/隐藏应用程序窗口
  • Toolbars:工具栏设置
  • Status Bar:状态栏显示

Tools 菜单

  • Options:全局设置
  • Plugins:插件管理
  • Platform:平台工具

Window 菜单

  • Reset Windows:重置窗口布局
  • Configure Window:配置窗口

Help 菜单

  • Contents:帮助文档
  • About:关于信息
1.2.2 工具栏 (Toolbar)
[🏠] [🔄] [📊] [🔍] [⚙️] [❓]Home Refresh Monitor Search Settings Help
  • Home:返回主页
  • Refresh:刷新当前视图
  • Monitor:快速监控
  • Search:搜索功能
  • Settings:快速设置
  • Help:帮助信息
1.2.3 应用程序树 (Applications Tree)

Local 节点

  • 显示本地运行的 Java 进程
  • 自动发现和刷新
  • 显示进程 PID 和主类名

Remote 节点

  • 远程 JVM 连接
  • 需要手动添加
  • 支持 JMX 连接

Snapshots 节点

  • 保存的快照文件
  • 堆转储文件
  • 线程转储文件
  • 性能分析结果

1.3 主视图区域

主视图区域采用标签页设计,支持多个视图同时打开:

┌─────────────────────────────────────────────────────────────┐
│ [Overview] [Monitor] [Threads] [Sampler] [Profiler] [MBeans]│
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                    当前选中的视图内容                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2. 应用程序连接和管理

2.1 本地应用程序连接

2.1.1 自动发现

VisualVM 会自动发现本地运行的 Java 应用程序:

# 启动一个测试应用程序
java -cp . TestApplication# VisualVM 会在 Local 节点下显示这个进程
# 格式:进程名 (PID)
# 例如:TestApplication (12345)
2.1.2 连接到应用程序
  1. 双击连接

    • 在应用程序树中双击进程
    • 自动打开 Overview 标签页
  2. 右键菜单

    右键点击进程 → 选择操作
    ├── Open
    ├── Thread Dump
    ├── Heap Dump
    ├── Profile
    ├── Properties
    └── Kill Application
    
2.1.3 应用程序信息查看
// 创建一个示例应用程序用于演示
public class MonitoringDemo {private static final int THREAD_COUNT = 5;private static final int MEMORY_SIZE = 1000000;public static void main(String[] args) throws InterruptedException {System.out.println("Monitoring Demo Started");// 创建多个线程for (int i = 0; i < THREAD_COUNT; i++) {new Thread(new WorkerTask("Worker-" + i)).start();}// 主线程持续运行while (true) {// 分配一些内存allocateMemory();Thread.sleep(5000);}}private static void allocateMemory() {// 创建一些对象来观察内存使用java.util.List<String> list = new java.util.ArrayList<>();for (int i = 0; i < MEMORY_SIZE; i++) {list.add("Data-" + i);}// 模拟一些处理时间try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}static class WorkerTask implements Runnable {private final String name;public WorkerTask(String name) {this.name = name;}@Overridepublic void run() {while (true) {try {// 模拟工作负载doWork();Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}}}private void doWork() {// 模拟 CPU 密集型工作double result = 0;for (int i = 0; i < 100000; i++) {result += Math.sqrt(i) * Math.sin(i);}System.out.println(name + " completed work: " + result);}}
}

2.2 远程应用程序连接

2.2.1 配置远程 JVM

启动远程应用程序

# 基本 JMX 配置
java -Dcom.sun.management.jmxremote \-Dcom.sun.management.jmxremote.port=9999 \-Dcom.sun.management.jmxremote.authenticate=false \-Dcom.sun.management.jmxremote.ssl=false \-Djava.rmi.server.hostname=192.168.1.100 \YourApplication# 带认证的配置
java -Dcom.sun.management.jmxremote \-Dcom.sun.management.jmxremote.port=9999 \-Dcom.sun.management.jmxremote.authenticate=true \-Dcom.sun.management.jmxremote.ssl=true \-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password \-Dcom.sun.management.jmxremote.access.file=/path/to/jmxremote.access \YourApplication

创建认证文件

# jmxremote.password
monitorRole  password123
controlRole  password456# jmxremote.access
monitorRole  readonly
controlRole  readwrite# 设置文件权限
chmod 600 jmxremote.password
chmod 644 jmxremote.access
2.2.2 在 VisualVM 中添加远程连接
  1. 添加远程主机

    右键点击 "Remote" → "Add Remote Host"
    输入主机名或 IP 地址:192.168.1.100
    
  2. 添加 JMX 连接

    右键点击远程主机 → "Add JMX Connection"
    连接字符串:service:jmx:rmi:///jndi/rmi://192.168.1.100:9999/jmxrmi
    用户名:monitorRole
    密码:password123
    
  3. 高级连接配置

    # 自定义连接脚本
    #!/bin/bash
    # remote-connect.shHOST="$1"
    PORT="$2"
    USER="$3"
    PASS="$4"if [[ -z $HOST || -z $PORT ]]; thenecho "Usage: $0 <host> <port> [username] [password]"exit 1
    fiCONNECTION_URL="service:jmx:rmi:///jndi/rmi://$HOST:$PORT/jmxrmi"echo "Connecting to: $CONNECTION_URL"if [[ -n $USER && -n $PASS ]]; thenecho "Using authentication: $USER"
    fi# 可以在这里添加更多的连接逻辑
    

2.3 应用程序管理

2.3.1 应用程序属性查看
右键点击应用程序 → Properties显示信息包括:
├── 基本信息
│   ├── 进程 ID (PID)
│   ├── 主类名
│   ├── 启动时间
│   └── 运行时间
├── JVM 信息
│   ├── Java 版本
│   ├── JVM 供应商
│   ├── JVM 参数
│   └── 类路径
├── 系统属性
│   ├── 操作系统信息
│   ├── 用户信息
│   └── 环境变量
└── JVM 参数├── 堆内存设置├── 垃圾收集器└── 其他 JVM 选项
2.3.2 应用程序控制

生成转储文件

# 通过 VisualVM 界面
右键点击应用程序 → Thread Dump  # 生成线程转储
右键点击应用程序 → Heap Dump    # 生成堆转储# 通过命令行(备用方法)
jstack <PID> > thread_dump.txt
jmap -dump:format=b,file=heap_dump.hprof <PID>

终止应用程序

右键点击应用程序 → Kill Application
注意:这会强制终止进程,可能导致数据丢失

3. Overview 标签页详解

3.1 Overview 界面布局

┌─────────────────────────────────────────────────────────────┐
│                        Overview                             │
├─────────────────────────────────────────────────────────────┤
│  应用程序信息 (Application Information)                      │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ PID: 12345                    Started: 2024-01-15 10:30 │ │
│  │ Host: localhost               Arguments: -Xmx2g -server  │ │
│  │ Main class: com.example.App   JVM: OpenJDK 11.0.2       │ │
│  └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│  JVM 参数 (JVM Arguments)                                   │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ -Xms512m -Xmx2g -XX:+UseG1GC -server                   │ │
│  │ -Dfile.encoding=UTF-8 -Djava.awt.headless=true         │ │
│  └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│  系统属性 (System Properties)                               │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ java.version: 11.0.2                                   │ │
│  │ os.name: Linux                                          │ │
│  │ user.dir: /home/user/project                           │ │
│  │ [Show All Properties...]                               │ │
│  └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

3.2 应用程序信息解读

3.2.1 基本信息

进程信息

  • PID:进程标识符,用于系统级操作
  • Host:运行主机,本地显示为 localhost
  • Started:应用程序启动时间
  • Main class:主类名,应用程序入口点

JVM 信息

  • JVM 版本:Java 虚拟机版本和供应商
  • JVM 模式:Client 或 Server 模式
  • 架构:32位或64位
3.2.2 JVM 参数分析

内存参数

-Xms512m        # 初始堆大小
-Xmx2g          # 最大堆大小
-XX:NewRatio=3  # 新生代与老年代比例
-XX:MaxMetaspaceSize=256m  # 元空间最大大小

垃圾收集器参数

-XX:+UseG1GC              # 使用 G1 垃圾收集器
-XX:+UseParallelGC        # 使用并行垃圾收集器
-XX:+UseConcMarkSweepGC   # 使用 CMS 垃圾收集器
-XX:MaxGCPauseMillis=200  # 最大 GC 暂停时间

调试和监控参数

-XX:+PrintGC              # 打印 GC 信息
-XX:+PrintGCDetails       # 打印详细 GC 信息
-XX:+HeapDumpOnOutOfMemoryError  # OOM 时生成堆转储
-Dcom.sun.management.jmxremote   # 启用 JMX 远程监控

3.3 系统属性查看

3.3.1 重要系统属性

Java 相关属性

java.version=11.0.2
java.vendor=Eclipse Adoptium
java.home=/usr/lib/jvm/java-11-openjdk
java.class.path=/app/lib/*:/app/classes
java.library.path=/usr/lib/x86_64-linux-gnu

操作系统属性

os.name=Linux
os.version=5.4.0-74-generic
os.arch=amd64
file.separator=/
path.separator=:
line.separator=\n

用户和目录属性

user.name=appuser
user.home=/home/appuser
user.dir=/app
user.timezone=Asia/Shanghai
file.encoding=UTF-8
3.3.2 自定义属性查看
// 在应用程序中设置自定义属性
public class PropertyDemo {public static void main(String[] args) {// 设置自定义系统属性System.setProperty("app.name", "MyApplication");System.setProperty("app.version", "1.0.0");System.setProperty("app.environment", "production");System.setProperty("app.config.file", "/etc/myapp/config.properties");// 打印所有系统属性System.getProperties().forEach((key, value) -> {if (key.toString().startsWith("app.")) {System.out.println(key + "=" + value);}});// 保持应用程序运行try {Thread.sleep(Long.MAX_VALUE);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}

4. Monitor 标签页详解

4.1 Monitor 界面布局

┌─────────────────────────────────────────────────────────────┐
│                        Monitor                              │
├─────────────────────────────────────────────────────────────┤
│  CPU 使用率图表                                              │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │     CPU Usage (%)                                      │ │
│  │ 100 ┤                                                  │ │
│  │  80 ┤     ██                                           │ │
│  │  60 ┤   ████                                           │ │
│  │  40 ┤ ██████                                           │ │
│  │  20 ┤████████                                          │ │
│  │   0 └────────────────────────────────────────────────── │ │
│  │     0    1    2    3    4    5    6    7    8    9   10 │ │
│  │                        Time (minutes)                  │ │
│  └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│  内存使用图表                                                │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │     Memory Usage (MB)                                  │ │
│  │2048 ┤                                                  │ │
│  │1536 ┤                                                  │ │
│  │1024 ┤     ████████████████████████████████████████████ │ │
│  │ 512 ┤ ████████████████████████████████████████████████ │ │
│  │   0 └────────────────────────────────────────────────── │ │
│  │     0    1    2    3    4    5    6    7    8    9   10 │ │
│  │     Heap: 1024MB  Used: 512MB  Max: 2048MB            │ │
│  └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│  类和线程信息                                                │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ Classes: 8,432 loaded, 0 unloaded                     │ │
│  │ Threads: 25 live, 28 peak                             │ │
│  └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

4.2 CPU 监控

4.2.1 CPU 使用率指标

CPU 使用率类型

  • Process CPU:当前进程的 CPU 使用率
  • System CPU:整个系统的 CPU 使用率
  • GC CPU:垃圾收集占用的 CPU 时间

CPU 使用率计算

// 获取 CPU 使用率的示例代码
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;public class CPUMonitor {private static final OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();public static void main(String[] args) throws InterruptedException {while (true) {// 获取系统 CPU 使用率double systemCpuLoad = osBean.getSystemCpuLoad();// 获取进程 CPU 使用率double processCpuLoad = osBean.getProcessCpuLoad();System.out.printf("System CPU: %.2f%%, Process CPU: %.2f%%\n", systemCpuLoad * 100, processCpuLoad * 100);Thread.sleep(5000);}}
}
4.2.2 CPU 使用率分析

正常 CPU 使用模式

  • 稳定型:CPU 使用率相对稳定,波动较小
  • 周期型:CPU 使用率呈现周期性变化
  • 突发型:偶尔出现 CPU 使用率峰值

异常 CPU 使用模式

  • 持续高使用率:可能存在死循环或计算密集型操作
  • 频繁波动:可能存在资源竞争或线程调度问题
  • 异常峰值:可能存在性能瓶颈或算法问题

4.3 内存监控

4.3.1 内存区域详解

堆内存 (Heap Memory)

堆内存结构:
┌─────────────────────────────────────────────────────────┐
│                    Java Heap                           │
├─────────────────────────────────────────────────────────┤
│  新生代 (Young Generation)                              │
│  ┌─────────────┬─────────────┬─────────────────────────┐ │
│  │    Eden     │ Survivor S0 │     Survivor S1         │ │
│  │   Space     │    Space    │       Space             │ │
│  └─────────────┴─────────────┴─────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│  老年代 (Old Generation / Tenured Space)               │
│  ┌─────────────────────────────────────────────────────┐ │
│  │                                                     │ │
│  │              Old Generation                         │ │
│  │                                                     │ │
│  └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘

非堆内存 (Non-Heap Memory)

  • Metaspace:类元数据存储区域(Java 8+)
  • Code Cache:编译后的本地代码缓存
  • Compressed Class Space:压缩类指针空间
4.3.2 内存使用指标

关键指标

// 内存监控示例
import java.lang.management.*;
import java.util.List;public class MemoryMonitor {private static final MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();private static final List<MemoryPoolMXBean> memoryPools = ManagementFactory.getMemoryPoolMXBeans();public static void printMemoryInfo() {// 堆内存信息MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();System.out.println("=== Heap Memory ===");System.out.println("Used: " + formatBytes(heapUsage.getUsed()));System.out.println("Committed: " + formatBytes(heapUsage.getCommitted()));System.out.println("Max: " + formatBytes(heapUsage.getMax()));System.out.println("Usage: " + String.format("%.2f%%", (double) heapUsage.getUsed() / heapUsage.getMax() * 100));// 非堆内存信息MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage();System.out.println("\n=== Non-Heap Memory ===");System.out.println("Used: " + formatBytes(nonHeapUsage.getUsed()));System.out.println("Committed: " + formatBytes(nonHeapUsage.getCommitted()));// 各内存池详细信息System.out.println("\n=== Memory Pools ===");for (MemoryPoolMXBean pool : memoryPools) {MemoryUsage usage = pool.getUsage();System.out.printf("%s: %s / %s (%.2f%%)\n",pool.getName(),formatBytes(usage.getUsed()),formatBytes(usage.getMax()),usage.getMax() > 0 ? (double) usage.getUsed() / usage.getMax() * 100 : 0);}}private static String formatBytes(long bytes) {if (bytes < 1024) return bytes + " B";if (bytes < 1024 * 1024) return String.format("%.2f KB", bytes / 1024.0);if (bytes < 1024 * 1024 * 1024) return String.format("%.2f MB", bytes / (1024.0 * 1024));return String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024));}public static void main(String[] args) throws InterruptedException {while (true) {printMemoryInfo();System.out.println("\n" + "=".repeat(50) + "\n");Thread.sleep(10000);}}
}
4.3.3 内存使用模式分析

正常内存使用模式

  • 锯齿型:内存使用逐渐增长,GC 后下降
  • 稳定型:内存使用相对稳定,在一定范围内波动
  • 阶梯型:内存使用呈阶梯式增长,每次 GC 后有所下降

异常内存使用模式

  • 持续增长:可能存在内存泄漏
  • 频繁 GC:可能存在内存不足或对象创建过于频繁
  • 突然下降:可能发生了 Full GC 或应用程序重启

4.4 类和线程监控

4.4.1 类加载监控

类加载指标

  • Loaded Classes:当前已加载的类数量
  • Total Loaded:总共加载过的类数量
  • Unloaded Classes:已卸载的类数量
// 类加载监控示例
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.ManagementFactory;public class ClassLoadingMonitor {private static final ClassLoadingMXBean classLoadingBean = ManagementFactory.getClassLoadingMXBean();public static void printClassLoadingInfo() {System.out.println("=== Class Loading Information ===");System.out.println("Loaded Classes: " + classLoadingBean.getLoadedClassCount());System.out.println("Total Loaded: " + classLoadingBean.getTotalLoadedClassCount());System.out.println("Unloaded Classes: " + classLoadingBean.getUnloadedClassCount());// 计算类加载率long totalLoaded = classLoadingBean.getTotalLoadedClassCount();long unloaded = classLoadingBean.getUnloadedClassCount();double retentionRate = (double) (totalLoaded - unloaded) / totalLoaded * 100;System.out.printf("Class Retention Rate: %.2f%%\n", retentionRate);}public static void main(String[] args) throws InterruptedException {while (true) {printClassLoadingInfo();System.out.println();Thread.sleep(5000);}}
}
4.4.2 线程监控

线程指标

  • Live Threads:当前活跃线程数
  • Peak Threads:历史最大线程数
  • Daemon Threads:守护线程数
  • Total Started:总共启动过的线程数
// 线程监控示例
import java.lang.management.ThreadMXBean;
import java.lang.management.ManagementFactory;public class ThreadMonitor {private static final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();public static void printThreadInfo() {System.out.println("=== Thread Information ===");System.out.println("Live Threads: " + threadBean.getThreadCount());System.out.println("Peak Threads: " + threadBean.getPeakThreadCount());System.out.println("Daemon Threads: " + threadBean.getDaemonThreadCount());System.out.println("Total Started: " + threadBean.getTotalStartedThreadCount());// 获取所有线程信息long[] threadIds = threadBean.getAllThreadIds();System.out.println("\n=== Thread Details ===");for (long threadId : threadIds) {ThreadInfo threadInfo = threadBean.getThreadInfo(threadId);if (threadInfo != null) {System.out.printf("Thread [%d]: %s - %s\n",threadId,threadInfo.getThreadName(),threadInfo.getThreadState());}}}public static void main(String[] args) throws InterruptedException {while (true) {printThreadInfo();System.out.println("\n" + "=".repeat(50) + "\n");Thread.sleep(10000);}}
}

5. 实时监控最佳实践

5.1 监控策略

5.1.1 监控频率设置
# 在 VisualVM 中设置监控频率
# Tools → Options → Profiler → Settings# 推荐设置:
# - 开发环境:1-2 秒
# - 测试环境:5-10 秒
# - 生产环境:30-60 秒(如果允许)
5.1.2 监控数据保存
// 自动保存监控数据的脚本
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.lang.management.*;public class MonitoringDataSaver {private static final String DATA_DIR = "monitoring_data";private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");public static void saveMonitoringSnapshot() {try {File dataDir = new File(DATA_DIR);if (!dataDir.exists()) {dataDir.mkdirs();}String timestamp = LocalDateTime.now().format(FORMATTER);String filename = String.format("%s/monitoring_%s.txt", DATA_DIR, timestamp);try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {writer.println("=== Monitoring Snapshot ===");writer.println("Timestamp: " + LocalDateTime.now());writer.println();// 保存内存信息MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();writer.println("Heap Memory:");writer.println("  Used: " + heapUsage.getUsed());writer.println("  Max: " + heapUsage.getMax());writer.println("  Usage: " + String.format("%.2f%%", (double) heapUsage.getUsed() / heapUsage.getMax() * 100));writer.println();// 保存线程信息ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();writer.println("Thread Information:");writer.println("  Live: " + threadBean.getThreadCount());writer.println("  Peak: " + threadBean.getPeakThreadCount());writer.println("  Daemon: " + threadBean.getDaemonThreadCount());writer.println();// 保存类加载信息ClassLoadingMXBean classBean = ManagementFactory.getClassLoadingMXBean();writer.println("Class Loading:");writer.println("  Loaded: " + classBean.getLoadedClassCount());writer.println("  Total: " + classBean.getTotalLoadedClassCount());writer.println("  Unloaded: " + classBean.getUnloadedClassCount());}System.out.println("Monitoring data saved to: " + filename);} catch (IOException e) {System.err.println("Failed to save monitoring data: " + e.getMessage());}}public static void main(String[] args) throws InterruptedException {// 每分钟保存一次监控数据while (true) {saveMonitoringSnapshot();Thread.sleep(60000); // 60 seconds}}
}

5.2 性能影响最小化

5.2.1 监控开销控制
// 轻量级监控实现
public class LightweightMonitor {private static final long MONITOR_INTERVAL = 30000; // 30 secondsprivate static volatile boolean monitoring = true;public static void startMonitoring() {Thread monitorThread = new Thread(() -> {MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();while (monitoring) {try {// 只收集关键指标MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();double heapUsagePercent = (double) heapUsage.getUsed() / heapUsage.getMax() * 100;int threadCount = threadBean.getThreadCount();// 简单的阈值检查if (heapUsagePercent > 80) {System.out.println("WARNING: High heap usage: " + String.format("%.2f%%", heapUsagePercent));}if (threadCount > 100) {System.out.println("WARNING: High thread count: " + threadCount);}Thread.sleep(MONITOR_INTERVAL);} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}}});monitorThread.setDaemon(true);monitorThread.setName("LightweightMonitor");monitorThread.start();}public static void stopMonitoring() {monitoring = false;}
}

5.3 监控告警

5.3.1 简单告警系统
// 监控告警系统
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.List;
import java.util.ArrayList;public class MonitoringAlertSystem {private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);private final List<AlertRule> alertRules = new ArrayList<>();public static class AlertRule {private final String name;private final Supplier<Double> valueSupplier;private final double threshold;private final String operator; // ">", "<", ">=", "<="private boolean alerted = false;public AlertRule(String name, Supplier<Double> valueSupplier, String operator, double threshold) {this.name = name;this.valueSupplier = valueSupplier;this.operator = operator;this.threshold = threshold;}public boolean check() {double value = valueSupplier.get();boolean shouldAlert = false;switch (operator) {case ">":shouldAlert = value > threshold;break;case "<":shouldAlert = value < threshold;break;case ">=":shouldAlert = value >= threshold;break;case "<=":shouldAlert = value <= threshold;break;}if (shouldAlert && !alerted) {System.out.printf("ALERT: %s = %.2f %s %.2f\n", name, value, operator, threshold);alerted = true;return true;} else if (!shouldAlert && alerted) {System.out.printf("RESOLVED: %s = %.2f\n", name, value);alerted = false;}return false;}}public void addAlertRule(AlertRule rule) {alertRules.add(rule);}public void startMonitoring() {scheduler.scheduleAtFixedRate(() -> {for (AlertRule rule : alertRules) {rule.check();}}, 0, 30, TimeUnit.SECONDS);}public void shutdown() {scheduler.shutdown();}public static void main(String[] args) throws InterruptedException {MonitoringAlertSystem alertSystem = new MonitoringAlertSystem();MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();// 添加告警规则alertSystem.addAlertRule(new AlertRule("Heap Usage %",() -> {MemoryUsage usage = memoryBean.getHeapMemoryUsage();return (double) usage.getUsed() / usage.getMax() * 100;},">",80.0));alertSystem.addAlertRule(new AlertRule("Thread Count",() -> (double) threadBean.getThreadCount(),">",50.0));alertSystem.startMonitoring();// 保持程序运行Thread.sleep(Long.MAX_VALUE);}
}

6. 本章总结

6.1 关键要点

  1. 用户界面掌握

    • 熟悉 VisualVM 的界面布局和组件
    • 理解各个标签页的功能和用途
    • 掌握应用程序连接和管理方法
  2. 基本监控技能

    • CPU 使用率监控和分析
    • 内存使用监控和模式识别
    • 类加载和线程状态监控
    • 实时数据的解读和分析
  3. 监控最佳实践

    • 合理设置监控频率
    • 最小化性能影响
    • 建立告警机制
    • 数据保存和分析

6.2 实践建议

  1. 循序渐进

    • 从简单的本地应用开始
    • 逐步尝试远程监控
    • 深入理解各项指标含义
  2. 结合实际

    • 在实际项目中应用监控
    • 建立性能基线
    • 识别性能瓶颈
  3. 持续学习

    • 关注新版本功能
    • 学习高级监控技巧
    • 分享监控经验

6.3 下一步学习

在下一章中,我们将学习:

  • 线程分析和死锁检测
  • 线程转储的生成和分析
  • 线程状态的深入理解
  • 并发问题的诊断技巧

通过本章的学习,您已经掌握了 VisualVM 的基本使用方法和监控技能,为深入的性能分析打下了坚实的基础。

http://www.xdnf.cn/news/1432117.html

相关文章:

  • Ansible 循环、过滤器与判断逻辑
  • 小学一到六年级语文/英语/数学作业出题布置网站源码 支持生成PDF和打印
  • 基金交易量预测比赛_数据分析
  • MySQL 8.0 窗口函数详解:让数据分析更简单高效
  • 大数据毕业设计选题推荐-基于大数据的大学生就业因素数据分析系统-Spark-Hadoop-Bigdata
  • 华为OD最新机试真题-中庸行者-OD统一考试(C卷)
  • 【Unity Shader学习笔记】(二)图形显示系统
  • 从Web2到Web3:一场重塑数字未来的“静默革命”
  • mac 本地安装maven环境
  • LLM面试50问:NLP/RAG/部署/对齐/安全/多模态全覆盖
  • CentOS7.6
  • @Hadoop 介绍部署使用详细指南
  • Qt中QSettings的键值使用QDataStream进行存储
  • 【ComfyUI】SDXL Refiner 提示进一步提升生成图像的质量
  • Android的USB通信 (AOA Android开放配件协议)
  • CSS基础学习步骤
  • 蓝桥杯算法之基础知识(5)
  • GPU 优化 - tensor core 用swizzle 解决bank conflict
  • STM32HAL 快速入门(十六):UART 协议 —— 异步串行通信的底层逻辑
  • PyTorch 训练随机卡死复盘:DataLoader × OpenCV 多进程死锁,三步定位与彻底修复
  • 【lucene】advanceshallow就是遍历跳表的,可以看作是跳表的遍历器
  • vscode下leetcode插件cookie登录
  • MySQL进阶知识梳理
  • 如何用c来编写一个判断闰年平年的微程序呢
  • 静态网站生成利器 Eleventy
  • 大文件稳定上传:Spring Boot + MinIO 断点续传实践
  • leetcode算法刷题的第二十四天
  • 网络数据包是怎么在客户端和服务端之间进行传输的?
  • 【Go语言并发编程:Goroutine调度原理】
  • Flink - 基础学习(1)-三种时间语义