jvm 线程信息诊断、stack 信息打印

java

浏览数:27

2019-1-13


JvmUtil.java


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
import java.lang.management.MonitorInfo;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * jvm数据
 * 
 */
public class JvmUtil {
    private transient static Log log = LogFactory.getLog(JvmUtil.class);
    /**
     * 打印线程堆栈深度
     */
    private static final int STACK_DEPP = 32;

    public final static int DUMP_MOD_FACT = Integer.valueOf(System.getProperty(
            "dump_mod_fact", "10080" /* 7 * 24 * 60 */));
    public final static String DUMP_DIR = System.getProperty("dump_dir",
            System.getProperty("user.home") + "/.appmonitor/stacks");
    public final static float DUMP_THRESHOLD = Float.valueOf(System
            .getProperty("dump_threshold", "0.5f"));

    public static void jstack(OutputStream stream) throws Exception {
        ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
        for (ThreadInfo threadInfo : threadMxBean.dumpAllThreads(true, true)) {
            stream.write(getThreadDumpString(threadInfo).getBytes());
        }
    }

    public static float computeThreadPrecent(long totalThreads, long busiThreads) {
        float threadPercent = 0f;
        if (totalThreads > 0)
            threadPercent = (float) Math
                    .round(((float) busiThreads / totalThreads) * 100) / 100;
        return threadPercent;
    }

    public static boolean isNeedDump(long totalThreads, long busiThreads) {
        return computeThreadPrecent(totalThreads, busiThreads) > DUMP_THRESHOLD;
    }

    public static void dump(String serverName, long serverId,
            ThreadInfo[] appThreadInfos) {
        String dumpFileName = dumpFileName(serverName, serverId);
        File file = new File(DUMP_DIR, dumpFileName);
        String msg = String.format("dump stack from %s-%s to path %s",
                serverName, serverId, file.getAbsolutePath());
        log.warn("start " + msg);
        File parentFile = file.getParentFile();
        if (!parentFile.exists())
            parentFile.mkdirs();
        if (file.exists())
            file.delete();
        try {
            file.createNewFile();
            JvmUtil.dumpStack(file, appThreadInfos);
            log.warn(String.format("start dump stack from %s-%s to path %s",
                    serverName, serverId, file.getAbsolutePath()));
            log.warn("finish " + msg);
        } catch (IOException e) {
            log.error("error " + msg, e);
        }
    }

    private static String dumpFileName(String serverName, long serverId) {
        return String.format("%s-%d-%d", serverName, serverId,
                System.currentTimeMillis() / 60000 % DUMP_MOD_FACT);
    }

    public static void dumpStack(File file, ThreadInfo[] threadInfos) {
        if (threadInfos == null || threadInfos.length == 0)
            return;
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            jstack(fos, threadInfos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null)
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }

    public static void jstack(OutputStream stream, ThreadInfo[] threadInfos)
            throws Exception {
        if (threadInfos == null)
            return;
        for (ThreadInfo threadInfo : threadInfos) {
            stream.write(getThreadDumpString(threadInfo).getBytes());
        }
    }

    private static String getThreadDumpString(ThreadInfo threadInfo) {
        StringBuilder sb = new StringBuilder("\"" + threadInfo.getThreadName()
                + "\"" + " Id=" + threadInfo.getThreadId() + " "
                + threadInfo.getThreadState());
        if (threadInfo.getLockName() != null) {
            sb.append(" on " + threadInfo.getLockName());
        }
        if (threadInfo.getLockOwnerName() != null) {
            sb.append(" owned by \"" + threadInfo.getLockOwnerName() + "\" Id="
                    + threadInfo.getLockOwnerId());
        }
        if (threadInfo.isSuspended()) {
            sb.append(" (suspended)");
        }
        if (threadInfo.isInNative()) {
            sb.append(" (in native)");
        }
        sb.append('\n');
        int i = 0;

        StackTraceElement[] stackTrace = threadInfo.getStackTrace();
        MonitorInfo[] lockedMonitors = threadInfo.getLockedMonitors();
        for (; i < stackTrace.length && i < STACK_DEPP; i++) {
            StackTraceElement ste = stackTrace[i];
            sb.append("\tat " + ste.toString());
            sb.append('\n');
            if (i == 0 && threadInfo.getLockInfo() != null) {
                Thread.State ts = threadInfo.getThreadState();
                switch (ts) {
                case BLOCKED:
                    sb.append("\t-  blocked on " + threadInfo.getLockInfo());
                    sb.append('\n');
                    break;
                case WAITING:
                    sb.append("\t-  waiting on " + threadInfo.getLockInfo());
                    sb.append('\n');
                    break;
                case TIMED_WAITING:
                    sb.append("\t-  waiting on " + threadInfo.getLockInfo());
                    sb.append('\n');
                    break;
                default:
                }
            }

            for (MonitorInfo mi : lockedMonitors) {
                if (mi.getLockedStackDepth() == i) {
                    sb.append("\t-  locked " + mi);
                    sb.append('\n');
                }
            }
        }
        if (i < stackTrace.length) {
            sb.append("\t...");
            sb.append('\n');
        }

        LockInfo[] locks = threadInfo.getLockedSynchronizers();
        if (locks.length > 0) {
            sb.append("\n\tNumber of locked synchronizers = " + locks.length);
            sb.append('\n');
            for (LockInfo li : locks) {
                sb.append("\t- " + li);
                sb.append('\n');
            }
        }
        sb.append('\n');
        return sb.toString();
    }
}

相关推荐