Skip to content

jcmd jstat

wangkaiwu edited this page Jun 26, 2022 · 2 revisions

jstat

使用样例

$ jstat -gc 4349
    S0C         S1C         S0U         S1U          EC           EU           OC           OU          MC         MU       CCSC      CCSU     YGC     YGCT     FGC    FGCT     CGC    CGCT       GCT   
    22016.0     12800.0         0.0     12370.4     125952.0     124167.3     182272.0      22049.5    58112.0    54113.0    8448.0    7736.6      9     0.158     2     0.051     -         -     0.209

显示源码

public class Jstat {
    private static Arguments arguments;

    public static void main(String[] args) {
        arguments = new Arguments(args);
        if (arguments.isOptions()) {
            OptionLister ol = new OptionLister(arguments.optionsSources());
            ol.print(System.out);
            System.exit(0);
        }

        logSamples();
    }
}

参数解析

public class Arguments {
    private boolean help;

    public Arguments(String[] args) throws IllegalArgumentException {
        int argc = 0;
        if (args.length == 0) {
            help = true;
            return;
        }
        if (args[0].compareTo("-options") == 0) {
            options = true;
            return;
        } else if (args[0].compareTo("-list") == 0) {
            list = true;
            argc++;
        }

        switch (args.length - argc) {
            case 3:
                interval = toMillis(args[args.length - 2]);
                vmIdString = args[args.length - 3];
                break;
            case 2:
                interval = toMillis(args[args.length - 1]);
                vmIdString = args[args.length - 2];
            case 1:
                vmIdString = args[args.length - 1];
                break;
        }
        if (count == -1 && interval == -1) {
            count = 1;
            interval = 0;
        }
        vmId = new VmIdentifier(vmIdString);
    }
}

显示 -options 内容

public class JStat {
    static void logSamples() throws MonitorException {
        // jvm 进程Id
        final VmIdentifier vmId = arguments.vmId();
        // 间隔时间
        int interval = arguments.sampleInterval();
        final MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
        MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, interval);
        final JStatLogger logger = new JStatLogger(monitoredVm);

        OutputFormatter formatter = null;
        if (arguments.isSpecialOption()) {
            OptionFormat format = arguments.optionFormat();
            formatter = new OptionOutputFormatter(monitoredVm, format);
        }

        logger.logSamples(formatter, arguments.headerRate(),
                arguments.sampleInterval(), arguments.sampleCount(),
                System.out);
        monitoredHost.detach(monitoredVm);
    }
}

在 jdk.jcmd 包下有个 resource 目录,里面有个 jstat_options,记录了每个命令的 header

public class JStatLogger {
    public void logSamples(OutputFormatter formatter, int headerRate,
                           int sampleInterval, int sampleCount, PrintStream out)
            throws MonitorException {
        int printHeader = headerRate;
        if (printHeader == 0) {
            // 打印命令对应的 header
            out.println(formatter.getHeader());
            printHeader = -1;
        }
        while (active) {
            // 由于内容是一行一行显示的,所以很容易导致看不到 header了
            // 这里就是每隔几行就打印一下 header
            if (printHeader > 0 && --printHeaderCount <= 0) {
                printHeaderCount = printHeader;
                out.println(formatter.getHeader());
            }
            out.println(formatter.getRow());
            // sampleCount 是共计采样数量,如果超限了就退出
            if (sampleCount > 0 && ++iterationCount >= sampleCount) {
                break;
            }
            // 定时触发
            Thread.sleep(sampleInterval);
        }
    }
}

monitoredVm

public class MonitoredHostProvider extends MonitoredHost {
    public MonitoredVm getMonitoredVm(VmIdentifier vmid, int interval)
            throws MonitorException {
        VmIdentifier nvmid = hostId.resolve(vmid);
        return new LocalMonitoredVm(nvmid, interval);
    }
}
public class LocalMonitoredVm extends AbstractMonitoredVm {
    public LocalMonitoredVm(VmIdentifier vmid, int interval) throws MonitorException {
        super(vmid, interval);
        this.pdb = new PerfDataBuffer(vmid);
        listeners = new ArrayList<VmListener>();
    }
}
public class PerfDataBuffer extends AbstractPerfDataBuffer {
    public PerfDataBuffer(VmIdentifier vmid) throws MonitorException {
        ByteBuffer bb = perf.attach(vmid.getLocalVmId(), vmid.getMode());
        createPerfDataBuffer(bb, vmid.getLocalVmId());
    }
}

row 内容的产生

public class RowClosure implements Closure {
    private MonitoredVm vm;
    private StringBuilder row = new StringBuilder();

    public void visit(Object o, boolean hasNext) throws MonitorException {
        ColumnFormat c = (ColumnFormat) o;
        String s = null;
        Expression e = c.getExpression();
        ExpressionEvaluator ee = new ExpressionExecuter(vm);
        Object value = ee.evaluate(e);
        if (value instanceof String) {
            s = (String) value;
        } else if (value instanceof Number) {
            double d = ((Number) value).doubleValue();
            double scaledValue = c.getScale().scale(d);
            s = df.format(scaledValue);
        }
        s = c.getAlignment().align(s, c.getWidth());
        row.append(s);
        if (hasNext) {
            row.append(" ");
        }
    }
}

evaluate

public class ExpressionExecuter implements ExpressionEvaluator {
    public Object evaluate(Expression e) {
        if (e instanceof Literal) {
            return ((Literal) e).getValue();
        }
        if (e instanceof Identifier) {
            Identifier id = (Identifier) e;
            if (map.containsKey(id.getName())) {
                return map.get(id.getName());
            } else {
                Monitor m = (Monitor) id.getValue();
                Object v = m.getValue();
                map.put(id.getName(), v);
                return v;
            }
        }
        Expression l = e.getLeft();
        Expression r = e.getRight();
        Operator op = e.getOperator();
        if (op == null) {
            return evaluate(l);
        } else {
            double lval = ((Number) evaluate(l)).doubleValue();
            double rval = ((Number) evaluate(r)).doubleValue();
            double result = op.eval(lval, rval);
            return Double.valueOf(result);
        }
    }
}

Expression

public class RowClosure implements Closure {
    public void visit(Object o, boolean hasNext) throws MonitorException {
        ColumnFormat c = (ColumnFormat)o;
        Expression e = c.getExpression();
    }
}
public class Parser {
    private void dataStmt(ColumnFormat cf) throws ParserException, IOException {
        match(DATA);
        Expression e = expression();
        // 上面的 getExpression() 对应的就是这里的 setExpression()
        cf.setExpression(e);
    }

    private Expression expression() throws ParserException, IOException {
        Expression e = addExpression();
        return e;
    }

    private Expression addExpression() throws ParserException, IOException {
        Expression e = multExpression();
        Operator op = null;
        while (true) {
            switch (lookahead.ttype) {
                case OPERATOR_PLUS:
                    match(OPERATOR_PLUS);
                    op = Operator.PLUS;
                    break;
                case OPERATOR_MINUS:
                    match(OPERATOR_MINUS);
                    op = Operator.MINUS;
                    break;
                default:
                    return e;
            }
            Expression e1 = new Expression();
            e1.setOperator(op);
            e1.setLeft(e);
            e1.setRight(multExpression());
            e = e1;
        }
    }
}

perfdata 的 枚举

enum CounterNS {
    JAVA_NS,
    COM_NS,
    SUN_NS,
}

Clone this wiki locally