java监控JVM的内存使用情况等

本文介绍了一种使用Java实现的系统监控程序,通过引入oshi-core和jna等依赖,能够实时监控并打印出CPU使用率、内存使用情况、磁盘空间、线程数量等关键系统信息,每60秒更新一次。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     以下的程序监控参数的代码,有些是从网络上获取的,此处进行一个记录是为了以后如果要用到方便记录。

 

1、引入jar包,为了获取一些cpu的使用率等信息

  <dependency>
    <groupId>com.github.oshi</groupId>
        <artifactId>oshi-core</artifactId>
        <version>3.12.2</version>
    </dependency>
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna</artifactId>
        <version>5.2.0</version>
    </dependency>

    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna-platform</artifactId>
        <version>5.2.0</version>
    </dependency>

 

2、编写代码

/**
 * 系统监控
 *
 * @author huan.fu
 * @date 2018/12/3 - 18:44
 */
@Component
public class SystemMonitor {

	@PostConstruct
	public void init() {
		Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
			try {

				SystemInfo systemInfo = new SystemInfo();

				OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
				MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
				//椎内存使用情况
				MemoryUsage memoryUsage = memoryMXBean.getHeapMemoryUsage();

				//初始的总内存
				long initTotalMemorySize = memoryUsage.getInit();
				//最大可用内存
				long maxMemorySize = memoryUsage.getMax();
				//已使用的内存
				long usedMemorySize = memoryUsage.getUsed();

				// 操作系统
				String osName = System.getProperty("os.name");
				// 总的物理内存
				String totalMemorySize = new DecimalFormat("#.##").format(osmxb.getTotalPhysicalMemorySize() / 1024.0 / 1024 / 1024) + "G";
				// 剩余的物理内存
				String freePhysicalMemorySize = new DecimalFormat("#.##").format(osmxb.getFreePhysicalMemorySize() / 1024.0 / 1024 / 1024) + "G";
				// 已使用的物理内存
				String usedMemory = new DecimalFormat("#.##").format((osmxb.getTotalPhysicalMemorySize() - osmxb.getFreePhysicalMemorySize()) / 1024.0 / 1024 / 1024) + "G";
				// 获得线程总数
				ThreadGroup parentThread;
				for (parentThread = Thread.currentThread().getThreadGroup(); parentThread.getParent() != null; parentThread = parentThread.getParent()) {

				}

				int totalThread = parentThread.activeCount();

				// 磁盘使用情况
				File[] files = File.listRoots();
				for (File file : files) {
					String total = new DecimalFormat("#.#").format(file.getTotalSpace() * 1.0 / 1024 / 1024 / 1024) + "G";
					String free = new DecimalFormat("#.#").format(file.getFreeSpace() * 1.0 / 1024 / 1024 / 1024) + "G";
					String un = new DecimalFormat("#.#").format(file.getUsableSpace() * 1.0 / 1024 / 1024 / 1024) + "G";
					String path = file.getPath();
					System.err.println(path + "总:" + total + ",可用空间:" + un + ",空闲空间:" + free);
					System.err.println("=============================================");
				}


				System.err.println("操作系统:" + osName);
				System.err.println("程序启动时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(ManagementFactory.getRuntimeMXBean().getStartTime())));
				System.err.println("pid:" + System.getProperty("PID"));
				System.err.println("cpu核数:" + Runtime.getRuntime().availableProcessors());
				printlnCpuInfo(systemInfo);
				System.err.println("JAVA_HOME:" + System.getProperty("java.home"));
				System.err.println("JAVA_VERSION:" + System.getProperty("java.version"));
				System.err.println("USER_HOME:" + System.getProperty("user.home"));
				System.err.println("USER_NAME:" + System.getProperty("user.name"));
				System.err.println("初始的总内存(JVM):" + new DecimalFormat("#.#").format(initTotalMemorySize * 1.0 / 1024 / 1024) + "M");
				System.err.println("最大可用内存(JVM):" + new DecimalFormat("#.#").format(maxMemorySize * 1.0 / 1024 / 1024) + "M");
				System.err.println("已使用的内存(JVM):" + new DecimalFormat("#.#").format(usedMemorySize * 1.0 / 1024 / 1024) + "M");
				System.err.println("总的物理内存:" + totalMemorySize);
				System.err.println("总的物理内存:" + new DecimalFormat("#.##").format(systemInfo.getHardware().getMemory().getTotal() * 1.0 / 1024 / 1024 / 1024) + "M");
				System.err.println("剩余的物理内存:" + freePhysicalMemorySize);
				System.err.println("剩余的物理内存:" + new DecimalFormat("#.##").format(systemInfo.getHardware().getMemory().getAvailable() * 1.0 / 1024 / 1024 / 1024) + "M");
				System.err.println("已使用的物理内存:" + usedMemory);
				System.err.println("已使用的物理内存:" + new DecimalFormat("#.##").format((systemInfo.getHardware().getMemory().getTotal() - systemInfo.getHardware().getMemory().getAvailable()) * 1.0 / 1024 / 1024 / 1024) + "M");
				System.err.println("总线程数:" + totalThread);
				System.err.println("===========================");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}, 0, 60, TimeUnit.SECONDS);
	}

	/**
	 * 打印 CPU 信息
	 *
	 * @param systemInfo
	 */
	private void printlnCpuInfo(SystemInfo systemInfo) throws InterruptedException {
		CentralProcessor processor = systemInfo.getHardware().getProcessor();
		long[] prevTicks = processor.getSystemCpuLoadTicks();
		// 睡眠1s
		TimeUnit.SECONDS.sleep(1);
		long[] ticks = processor.getSystemCpuLoadTicks();
		long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
		long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
		long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
		long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
		long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
		long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
		long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
		long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
		long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
		System.err.println("cpu核数:" + processor.getLogicalProcessorCount());
		System.err.println("cpu系统使用率:" + new DecimalFormat("#.##%").format(cSys * 1.0 / totalCpu));
		System.err.println("cpu用户使用率:" + new DecimalFormat("#.##%").format(user * 1.0 / totalCpu));
		System.err.println("cpu当前等待率:" + new DecimalFormat("#.##%").format(iowait * 1.0 / totalCpu));
		System.err.println("cpu当前空闲率:" + new DecimalFormat("#.##%").format(idle * 1.0 / totalCpu));
		System.err.format("CPU load: %.1f%% (counting ticks)%n", processor.getSystemCpuLoadBetweenTicks() * 100);
		System.err.format("CPU load: %.1f%% (OS MXBean)%n", processor.getSystemCpuLoad() * 100);
	}
}

 

3、获取更多系统信息,参考如下网址

https://github.com/oshi/oshi

 

<think>我们正在回答用户的问题:如何监控 Tomcat 应用服务器的 JVM 内存使用情况。 根据用户提供的引用,我们可以总结出以下几种监控方法: 1. 使用 JMX 监控(引用[1]提到) 2. 通过 Tomcat 的管理界面(引用[4]提到) 3. 使用命令行工具(如jstat、jps等,但引用中没有直接提到,但属于常见方法,可补充) 4. 配置GC日志(引用[2]提到垃圾回收策略,可以延伸出通过GC日志分析内存使用) 注意:用户特别提到要参考站内引用,因此我们尽量使用引用中的方法,并适当补充常见方法。 另外,用户的问题中引用了四篇文献,其中: 引用[1]:使用JMX监控JVM内存 引用[2]:关于Tomcat的JVM设置建议 引用[3]:Linux下修改Tomcat内存的方法(但用户当前问题不涉及修改,而是监控) 引用[4]:通过Tomcat的管理界面(manager/status)查看内存使用情况 因此,我们的回答将重点围绕引用[1]和[4]展开,同时补充其他常用方法。 回答结构: 1. 使用Tomcat管理界面(Web界面) 2. 使用JMX远程监控 3. 使用命令行工具(jconsole, jvisualvm, jstat等) 4. 分析GC日志 5. 使用监控工具(如Prometheus+Grafana等,但引用中未提及,可简要提) 注意:由于引用[4]中提供了通过manager/status查看的方法,我们将详细描述配置步骤。 同时,根据用户之前的提问(调整Tomcat JVM内存参数),我们可以将监控作为后续调优的依据,因此监控方法要实用。 最后,生成相关问题。</think>### 如何监控 Tomcat 的 JVM 内存使用情况 监控 Tomcat 的 JVM 内存使用是性能调优和故障排查的关键步骤,以下是几种常用方法: #### 1. **使用 Tomcat 管理界面(Web 控制台)** [^4] **配置步骤**: 1. 编辑 `$CATALINA_HOME/conf/tomcat-users.xml` 添加管理用户: ```xml <role rolename="manager-gui"/> <user username="admin" password="admin123" roles="manager-gui"/> ``` 2. 重启 Tomcat 后访问: ``` http://<服务器IP>:8080/manager/status ``` 3. 登录后查看 **JVM 内存**区域: - 堆内存(Heap) - 非堆内存(Non-Heap) - 详细的内存池使用情况 #### 2. **通过 JMX 远程监控** [^1] **配置方法**: 1. 在 `catalina.sh`/`catalina.bat` 添加 JMX 参数: ```bash JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false" ``` 2. 使用监控工具连接: - **JConsole**:运行 `jconsole` 连接 `IP:9010` - **VisualVM**:更强大的监控分析工具 - **监控指标**: - 堆内存使用曲线 - GC 频率和耗时 - 类加载数量 #### 3. **命令行工具监控** ```bash # 查看 Tomcat 进程 ID ps -ef | grep tomcat # 监控内存使用(每 2 秒刷新) jstat -gcutil <PID> 2000 # 输出示例 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 100.00 68.12 30.25 94.12 85.24 15 0.123 2 0.456 0.579 ``` > **指标说明**: > - `E`:Eden 区使用率 > - `O`:老年代使用率 > - `YGC/FGC`:YoungGC/FullGC 次数 > - `GCT`:GC 总耗时 #### 4. **GC 日志分析** [^2] 在启动参数添加: ```bash JAVA_OPTS="$JAVA_OPTS -Xloggc:/path/to/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps" ``` 通过工具(如 [GCViewer](https://github.com/chewiebug/GCViewer))分析日志,识别内存泄漏和 GC 瓶颈。 #### 5. **APM 工具集成** - **Prometheus + Grafana**: 使用 [JMX Exporter](https://github.com/prometheus/jmx_exporter) 采集指标 - **Elastic APM**: 自动追踪 JVM 性能指标 - **商业工具**: Dynatrace、AppDynamics 等提供实时监控 > **最佳实践**: > 1. 生产环境建议同时启用 JMX 监控和 GC 日志 > 2. 设置内存阈值告警(如堆使用 > 80%) > 3. 定期分析内存趋势,预防 OOM[^2] --- ### 相关问题 1. **Tomcat 频繁 Full GC 可能是什么原因导致的?如何优化?** > 可能原因包括内存泄漏、堆空间不足或垃圾回收器配置不当。优化方法:分析堆转储文件、调整分代内存比例、更换垃圾回收器(如 G1)[^2]。 2. **如何配置 Tomcat 在内存溢出时自动生成堆转储文件?** > 添加 JVM 参数:`-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps`[^2]。 3. **Tomcat 的元空间(Metaspace)持续增长可能是什么问题?** > 通常由类加载器泄漏或动态类生成(如反射、代理)引起。可通过 `jcmd <PID> GC.class_stats` 分析类加载情况[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值