/* * (C) Copyright 2015-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * ohun@live.cn (夜色) */ package com.mpush.tools.common; import com.mpush.tools.thread.NamedThreadFactory; import com.mpush.tools.thread.ThreadNames; import com.mpush.tools.thread.pool.ThreadPoolManager; import com.sun.management.HotSpotDiagnosticMXBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.management.MBeanServer; import javax.management.ObjectName; import java.io.*; import java.lang.management.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.util.Iterator; import java.util.Map; import java.util.Set; public class JVMUtil { private static final String HOT_SPOT_BEAN_NAME = "com.sun.management:type=HotSpotDiagnostic"; private static final Logger LOGGER = LoggerFactory.getLogger(JVMUtil.class); private static HotSpotDiagnosticMXBean hotSpotMXBean; private static ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); public static void jstack(OutputStream stream) throws Exception { PrintStream out = new PrintStream(stream); boolean cpuTimeEnabled = threadMXBean.isThreadCpuTimeSupported() && threadMXBean.isThreadCpuTimeEnabled(); Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces(); for (Map.Entry<Thread, StackTraceElement[]> entry : map.entrySet()) { Thread t = entry.getKey(); StackTraceElement[] elements = entry.getValue(); ThreadInfo tt = threadMXBean.getThreadInfo(t.getId()); long tid = t.getId(); Thread.State state = t.getState(); long cpuTimeMillis = cpuTimeEnabled ? threadMXBean.getThreadCpuTime(tid) / 1000000 : -1; long userTimeMillis = cpuTimeEnabled ? threadMXBean.getThreadUserTime(tid) / 1000000 : -1; out.printf("%s id=%d state=%s deamon=%s priority=%s cpu[total=%sms,user=%sms]", t.getName(), tid, t.getState(), t.isDaemon(), t.getPriority(), cpuTimeMillis, userTimeMillis); final LockInfo lock = tt.getLockInfo(); if (lock != null && state != Thread.State.BLOCKED) { out.printf("%n - waiting on <0x%08x> (a %s)", lock.getIdentityHashCode(), lock.getClassName()); out.printf("%n - locked <0x%08x> (a %s)", lock.getIdentityHashCode(), lock.getClassName()); } else if (lock != null && state == Thread.State.BLOCKED) { out.printf("%n - waiting to lock <0x%08x> (a %s)", lock.getIdentityHashCode(), lock.getClassName()); } if (tt.isSuspended()) { out.print(" (suspended)"); } if (tt.isInNative()) { out.print(" (running in native)"); } out.println(); if (tt.getLockOwnerName() != null) { out.printf(" owned by %s id=%d%n", tt.getLockOwnerName(), tt.getLockOwnerId()); } final MonitorInfo[] monitors = tt.getLockedMonitors(); for (int i = 0; i < elements.length; i++) { final StackTraceElement element = elements[i]; out.printf(" at %s%n", element); for (int j = 1; j < monitors.length; j++) { final MonitorInfo monitor = monitors[j]; if (monitor.getLockedStackDepth() == i) { out.printf(" - locked %s%n", monitor); } } } out.println(); final LockInfo[] locks = tt.getLockedSynchronizers(); if (locks.length > 0) { out.printf(" Locked synchronizers: count = %d%n", locks.length); for (LockInfo l : locks) { out.printf(" - %s%n", l); } out.println(); } } } public static void dumpJstack(final String jvmPath) { ThreadPoolManager.I.newThread("dump-jstack-t", (() -> { File path = new File(jvmPath); if (path.exists() || path.mkdirs()) { File file = new File(path, System.currentTimeMillis() + "-jstack.log"); try (FileOutputStream out = new FileOutputStream(file)) { JVMUtil.jstack(out); } catch (Throwable t) { LOGGER.error("Dump JVM cache Error!", t); } } })).start(); } private static HotSpotDiagnosticMXBean getHotSpotMXBean() { try { return AccessController.doPrivileged(new PrivilegedExceptionAction<HotSpotDiagnosticMXBean>() { public HotSpotDiagnosticMXBean run() throws Exception { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); Set<ObjectName> s = server.queryNames(new ObjectName(HOT_SPOT_BEAN_NAME), null); Iterator<ObjectName> itr = s.iterator(); if (itr.hasNext()) { ObjectName name = itr.next(); HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy(server, name.toString(), HotSpotDiagnosticMXBean.class); return bean; } else { return null; } } }); } catch (Exception e) { LOGGER.error("getHotSpotMXBean Error!", e); return null; } } private static void initHotSpotMBean() throws Exception { if (hotSpotMXBean == null) { synchronized (JVMUtil.class) { if (hotSpotMXBean == null) { hotSpotMXBean = getHotSpotMXBean(); } } } } public static void jMap(String fileName, boolean live) { File f = new File(fileName, System.currentTimeMillis() + "-jmap.log"); String currentFileName = f.getPath(); try { initHotSpotMBean(); if (f.exists()) { f.delete(); } hotSpotMXBean.dumpHeap(currentFileName, live); } catch (Exception e) { LOGGER.error("dumpHeap Error!" + currentFileName, e); } } public static void dumpJmap(final String jvmPath) { ThreadPoolManager.I.newThread("dump-jmap-t", () -> jMap(jvmPath, false)).start(); } }