Path: blob/master/src/jdk.jconsole/share/classes/sun/tools/jconsole/MemoryTab.java
40948 views
/*1* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.tools.jconsole;2627import java.awt.*;28import java.awt.event.*;29import java.io.*;30import java.lang.management.*;31import java.lang.reflect.*;32import java.util.*;33import java.util.concurrent.*;3435import javax.accessibility.*;36import javax.management.*;37import javax.management.openmbean.CompositeData;38import javax.swing.*;39import javax.swing.border.*;404142import static sun.tools.jconsole.Formatter.*;43import static sun.tools.jconsole.Utilities.*;4445@SuppressWarnings("serial")46class MemoryTab extends Tab implements ActionListener, ItemListener {47JComboBox<Plotter> plotterChoice;48TimeComboBox timeComboBox;49JButton gcButton;5051PlotterPanel plotterPanel;52JPanel bottomPanel;53HTMLPane details;54PoolChart poolChart;5556ArrayList<Plotter> plotterList;57Plotter heapPlotter, nonHeapPlotter;5859private MemoryOverviewPanel overviewPanel;6061private static final String usedKey = "used";62private static final String committedKey = "committed";63private static final String maxKey = "max";64private static final String thresholdKey = "threshold";65private static final Color usedColor = Plotter.defaultColor;66private static final Color committedColor = null;67private static final Color maxColor = null;68private static final Color thresholdColor = Color.red;6970/*71Hierarchy of panels and layouts for this tab:7273MemoryTab (BorderLayout)7475North: topPanel (BorderLayout)7677Center: controlPanel (FlowLayout)78plotterChoice, timeComboBox7980East: topRightPanel (FlowLayout)81gcButton8283Center: plotterPanel8485Center: plotter8687South: bottomPanel (BorderLayout)8889Center: details90East: poolChart91*/929394public static String getTabName() {95return Messages.MEMORY;96}9798public MemoryTab(VMPanel vmPanel) {99super(vmPanel, getTabName());100101setLayout(new BorderLayout(0, 0));102setBorder(new EmptyBorder(4, 4, 3, 4));103104JPanel topPanel = new JPanel(new BorderLayout());105plotterPanel = new PlotterPanel(null);106bottomPanel = new JPanel(new BorderLayout());107108add(topPanel, BorderLayout.NORTH);109add(plotterPanel, BorderLayout.CENTER);110111JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 20, 5));112topPanel.add(controlPanel, BorderLayout.CENTER);113114// Plotter choice115plotterChoice = new JComboBox<Plotter>();116plotterChoice.addItemListener(this);117controlPanel.add(new LabeledComponent(Messages.CHART_COLON,118Resources.getMnemonicInt(Messages.CHART_COLON),119plotterChoice));120121// Range control122timeComboBox = new TimeComboBox();123controlPanel.add(new LabeledComponent(Messages.TIME_RANGE_COLON,124Resources.getMnemonicInt(Messages.TIME_RANGE_COLON),125timeComboBox));126127gcButton = new JButton(Messages.PERFORM_GC);128gcButton.setMnemonic(Resources.getMnemonicInt(Messages.PERFORM_GC));129gcButton.addActionListener(this);130gcButton.setToolTipText(Messages.PERFORM_GC_TOOLTIP);131JPanel topRightPanel = new JPanel();132topRightPanel.setBorder(new EmptyBorder(0, 65-8, 0, 70));133topRightPanel.add(gcButton);134topPanel.add(topRightPanel, BorderLayout.AFTER_LINE_ENDS);135136bottomPanel.setBorder(new CompoundBorder(new TitledBorder(Messages.DETAILS),137new EmptyBorder(10, 10, 10, 10)));138139details = new HTMLPane();140setAccessibleName(details, Messages.DETAILS);141bottomPanel.add(new JScrollPane(details), BorderLayout.CENTER);142143poolChart = new PoolChart();144bottomPanel.add(poolChart, BorderLayout.AFTER_LINE_ENDS);145}146147148private void createPlotters() throws IOException {149plotterList = new ArrayList<Plotter>();150151ProxyClient proxyClient = vmPanel.getProxyClient();152153heapPlotter = new Plotter(Plotter.Unit.BYTES) {154public String toString() {155return Messages.HEAP_MEMORY_USAGE;156}157};158proxyClient.addWeakPropertyChangeListener(heapPlotter);159160nonHeapPlotter = new Plotter(Plotter.Unit.BYTES) {161public String toString() {162return Messages.NON_HEAP_MEMORY_USAGE;163}164};165166setAccessibleName(heapPlotter,167Messages.MEMORY_TAB_HEAP_PLOTTER_ACCESSIBLE_NAME);168setAccessibleName(nonHeapPlotter,169Messages.MEMORY_TAB_NON_HEAP_PLOTTER_ACCESSIBLE_NAME);170171proxyClient.addWeakPropertyChangeListener(nonHeapPlotter);172173heapPlotter.createSequence(usedKey, Messages.USED, usedColor, true);174heapPlotter.createSequence(committedKey, Messages.COMMITTED, committedColor, false);175heapPlotter.createSequence(maxKey, Messages.MAX, maxColor, false);176177nonHeapPlotter.createSequence(usedKey, Messages.USED, usedColor, true);178nonHeapPlotter.createSequence(committedKey, Messages.COMMITTED, committedColor, false);179nonHeapPlotter.createSequence(maxKey, Messages.MAX, maxColor, false);180181plotterList.add(heapPlotter);182plotterList.add(nonHeapPlotter);183184// Now add memory pools185Map<ObjectName, MBeanInfo> mBeanMap = proxyClient.getMBeans("java.lang");186Set<ObjectName> keys = mBeanMap.keySet();187ObjectName[] objectNames = keys.toArray(new ObjectName[keys.size()]);188ArrayList<PoolPlotter> nonHeapPlotters = new ArrayList<PoolPlotter>(2);189for (ObjectName objectName : objectNames) {190String type = objectName.getKeyProperty("type");191if (type.equals("MemoryPool")) {192String name = Resources.format(Messages.MEMORY_POOL_LABEL,193objectName.getKeyProperty("name"));194// Heap or non-heap?195boolean isHeap = false;196AttributeList al =197proxyClient.getAttributes(objectName,198new String[] { "Type" });199if (al.size() > 0) {200isHeap = MemoryType.HEAP.name().equals(((Attribute)al.get(0)).getValue());201}202PoolPlotter poolPlotter = new PoolPlotter(objectName, name, isHeap);203proxyClient.addWeakPropertyChangeListener(poolPlotter);204205poolPlotter.createSequence(usedKey, Messages.USED, usedColor, true);206poolPlotter.createSequence(committedKey, Messages.COMMITTED, committedColor, false);207poolPlotter.createSequence(maxKey, Messages.MAX, maxColor, false);208poolPlotter.createSequence(thresholdKey, Messages.THRESHOLD, thresholdColor, false);209poolPlotter.setUseDashedTransitions(thresholdKey, true);210211if (isHeap) {212plotterList.add(poolPlotter);213} else {214// Will be added to plotterList below215nonHeapPlotters.add(poolPlotter);216}217}218}219// Add non-heap plotters last220for (PoolPlotter poolPlotter : nonHeapPlotters) {221plotterList.add(poolPlotter);222}223}224225226public void itemStateChanged(ItemEvent ev) {227if (ev.getStateChange() == ItemEvent.SELECTED) {228Plotter plotter = (Plotter)plotterChoice.getSelectedItem();229plotterPanel.setPlotter(plotter);230plotterPanel.repaint();231}232}233234public void gc() {235new Thread("MemoryPanel.gc") {236public void run() {237ProxyClient proxyClient = vmPanel.getProxyClient();238try {239proxyClient.getMemoryMXBean().gc();240} catch (UndeclaredThrowableException e) {241proxyClient.markAsDead();242} catch (IOException e) {243// Ignore244}245}246}.start();247}248249public SwingWorker<?, ?> newSwingWorker() {250return new SwingWorker<Boolean, Object>() {251private long[] used, committed, max, threshold;252private long timeStamp;253private String detailsStr;254private boolean initialRun = false;255256public Boolean doInBackground() {257ProxyClient proxyClient = vmPanel.getProxyClient();258259if (plotterList == null) {260try {261createPlotters();262} catch (UndeclaredThrowableException e) {263proxyClient.markAsDead();264return false;265} catch (final IOException ex) {266return false;267}268initialRun = true;269}270271int n = plotterList.size();272used = new long[n];273committed = new long[n];274max = new long[n];275threshold = new long[n];276timeStamp = System.currentTimeMillis();277278for (int i = 0; i < n; i++) {279Plotter plotter = plotterList.get(i);280MemoryUsage mu = null;281used[i] = -1L;282threshold[i] = -1L;283284try {285if (plotter instanceof PoolPlotter) {286PoolPlotter poolPlotter = (PoolPlotter)plotter;287ObjectName objectName = poolPlotter.objectName;288AttributeList al =289proxyClient.getAttributes(objectName,290new String[] { "Usage", "UsageThreshold" });291if (al.size() > 0) {292CompositeData cd = (CompositeData)((Attribute)al.get(0)).getValue();293mu = MemoryUsage.from(cd);294295if (al.size() > 1) {296threshold[i] = (Long)((Attribute)al.get(1)).getValue();297}298}299} else if (plotter == heapPlotter) {300mu = proxyClient.getMemoryMXBean().getHeapMemoryUsage();301} else if (plotter == nonHeapPlotter) {302mu = proxyClient.getMemoryMXBean().getNonHeapMemoryUsage();303}304} catch (UndeclaredThrowableException e) {305proxyClient.markAsDead();306return false;307} catch (IOException ex) {308// Skip this plotter309}310311if (mu != null) {312used[i] = mu.getUsed();313committed[i] = mu.getCommitted();314max[i] = mu.getMax();315}316}317detailsStr = formatDetails();318319return true;320}321322protected void done() {323try {324if (!get()) {325return;326}327} catch (InterruptedException ex) {328return;329} catch (ExecutionException ex) {330if (JConsole.isDebug()) {331ex.printStackTrace();332}333return;334}335336if (initialRun) {337// Add Memory Pools338for (Plotter p : plotterList) {339plotterChoice.addItem(p);340timeComboBox.addPlotter(p);341}342add(bottomPanel, BorderLayout.SOUTH);343}344345346int n = plotterList.size();347int poolCount = 0;348349for (int i = 0; i < n; i++) {350Plotter plotter = plotterList.get(i);351if (used[i] >= 0L) {352if (plotter instanceof PoolPlotter) {353plotter.addValues(timeStamp, used[i], committed[i], max[i], threshold[i]);354if (threshold[i] > 0L) {355plotter.setIsPlotted(thresholdKey, true);356}357poolChart.setValue(poolCount++, (PoolPlotter)plotter,358used[i], threshold[i], max[i]);359} else {360plotter.addValues(timeStamp, used[i], committed[i], max[i]);361}362363if (plotter == heapPlotter && overviewPanel != null) {364overviewPanel.getPlotter().addValues(timeStamp, used[i]);365overviewPanel.updateMemoryInfo(used[i], committed[i], max[i]);366}367}368}369details.setText(detailsStr);370}371};372}373374private String formatDetails() {375ProxyClient proxyClient = vmPanel.getProxyClient();376if (proxyClient.isDead()) {377return "";378}379380String text = "<table cellspacing=0 cellpadding=0>";381382Plotter plotter = (Plotter)plotterChoice.getSelectedItem();383if (plotter == null) {384return "";385}386387//long time = plotter.getLastTimeStamp();388long time = System.currentTimeMillis();389String timeStamp = formatDateTime(time);390text += newRow(Messages.TIME, timeStamp);391392long used = plotter.getLastValue(usedKey);393long committed = plotter.getLastValue(committedKey);394long max = plotter.getLastValue(maxKey);395long threshold = plotter.getLastValue(thresholdKey);396397text += newRow(Messages.USED, formatKBytes(used));398if (committed > 0L) {399text += newRow(Messages.COMMITTED, formatKBytes(committed));400}401if (max > 0L) {402text += newRow(Messages.MAX, formatKBytes(max));403}404if (threshold > 0L) {405text += newRow(Messages.USAGE_THRESHOLD, formatKBytes(threshold));406}407408try {409Collection<GarbageCollectorMXBean> garbageCollectors =410proxyClient.getGarbageCollectorMXBeans();411412boolean descPrinted = false;413for (GarbageCollectorMXBean garbageCollectorMBean : garbageCollectors) {414String gcName = garbageCollectorMBean.getName();415long gcCount = garbageCollectorMBean.getCollectionCount();416long gcTime = garbageCollectorMBean.getCollectionTime();417String str = Resources.format(Messages.GC_TIME_DETAILS, justify(formatTime(gcTime), 14),418gcName,419String.format("%,d",gcCount));420if (!descPrinted) {421text += newRow(Messages.GC_TIME, str);422descPrinted = true;423} else {424text += newRow(null, str);425}426}427} catch (IOException e) {428}429430return text;431}432433public void actionPerformed(ActionEvent ev) {434Object src = ev.getSource();435if (src == gcButton) {436gc();437}438}439440private class PoolPlotter extends Plotter {441ObjectName objectName;442String name;443boolean isHeap;444long value, threshold, max;445int barX;446447public PoolPlotter(ObjectName objectName, String name, boolean isHeap) {448super(Plotter.Unit.BYTES);449450this.objectName = objectName;451this.name = name;452this.isHeap = isHeap;453454setAccessibleName(this,455Resources.format(Messages.MEMORY_TAB_POOL_PLOTTER_ACCESSIBLE_NAME,456name));457}458459460public String toString() {461return name;462}463}464465private class PoolChart extends BorderedComponent466implements Accessible, MouseListener {467final int height = 150;468final int leftMargin = 50;469final int rightMargin = 23;470final int bottomMargin = 35;471final int barWidth = 22;472final int barGap = 3;473final int groupGap = 8;474final int barHeight = height * 2 / 3;475476final Color greenBar = new Color(100, 255, 100);477final Color greenBarBackground = new Color(210, 255, 210);478final Color redBarBackground = new Color(255, 210, 210);479480Font smallFont = null;481482ArrayList<PoolPlotter> poolPlotters = new ArrayList<PoolPlotter>(5);483484int nHeapPools = 0;485int nNonHeapPools = 0;486Rectangle heapRect = new Rectangle(leftMargin, height - bottomMargin + 6, barWidth, 20);487Rectangle nonHeapRect = new Rectangle(leftMargin + groupGap, height - bottomMargin + 6, barWidth, 20);488489public PoolChart() {490super(null, null);491492setFocusable(true);493addMouseListener(this);494ToolTipManager.sharedInstance().registerComponent(this);495}496497public void setValue(int poolIndex, PoolPlotter poolPlotter,498long value, long threshold, long max) {499poolPlotter.value = value;500poolPlotter.threshold = threshold;501poolPlotter.max = max;502503if (poolIndex == poolPlotters.size()) {504poolPlotters.add(poolPlotter);505if (poolPlotter.isHeap) {506poolPlotter.barX = nHeapPools * (barWidth + barGap);507nHeapPools++;508heapRect.width = nHeapPools * barWidth + (nHeapPools - 1) * barGap;509nonHeapRect.x = leftMargin + heapRect.width + groupGap;510} else {511poolPlotter.barX = nonHeapRect.x - leftMargin + nNonHeapPools * (barWidth + barGap);512nNonHeapPools++;513nonHeapRect.width = nNonHeapPools * barWidth + (nNonHeapPools - 1) * barGap;514}515} else {516poolPlotters.set(poolIndex, poolPlotter);517}518repaint();519}520521private void paintPoolBar(Graphics g, PoolPlotter poolPlotter) {522Rectangle barRect = getBarRect(poolPlotter);523g.setColor(Color.gray);524g.drawRect(barRect.x, barRect.y, barRect.width, barRect.height);525526long value = poolPlotter.value;527long max = poolPlotter.max;528if (max > 0L) {529g.translate(barRect.x, barRect.y);530531// Paint green background532g.setColor(greenBarBackground);533g.fillRect(1, 1, barRect.width - 1, barRect.height - 1);534535int greenHeight = (int)(value * barRect.height / max);536long threshold = poolPlotter.threshold;537if (threshold > 0L) {538int redHeight = (int)(threshold * barRect.height / max);539540// Paint red background541g.setColor(redBarBackground);542g.fillRect(1, 1, barRect.width - 1, barRect.height - redHeight);543544if (value > threshold) {545// Over threshold, paint red bar546g.setColor(thresholdColor);547g.fillRect(1, barRect.height - greenHeight,548barRect.width - 1, greenHeight - redHeight);549greenHeight = redHeight;550}551}552553// Paint green bar554g.setColor(greenBar);555g.fillRect(1, barRect.height - greenHeight,556barRect.width - 1, greenHeight);557558g.translate(-barRect.x, -barRect.y);559}560}561562public void paintComponent(Graphics g) {563super.paintComponent(g);564565if (poolPlotters.size() == 0) {566return;567}568569if (smallFont == null) {570smallFont = g.getFont().deriveFont(9.0F);571}572573// Paint background for chart area574g.setColor(getBackground());575Rectangle r = g.getClipBounds();576g.fillRect(r.x, r.y, r.width, r.height);577578g.setFont(smallFont);579FontMetrics fm = g.getFontMetrics();580int fontDescent = fm.getDescent();581582// Paint percentage axis583g.setColor(getForeground());584for (int pc : new int[] { 0, 25, 50, 75, 100 }) {585String str = pc + "% --";586g.drawString(str,587leftMargin - fm.stringWidth(str) - 4,588height - bottomMargin - (pc * barHeight / 100) + fontDescent + 1);589}590591for (PoolPlotter poolPlotter : poolPlotters) {592paintPoolBar(g, poolPlotter);593}594595g.setColor(Color.gray);596g.drawRect(heapRect.x, heapRect.y, heapRect.width, heapRect.height);597g.drawRect(nonHeapRect.x, nonHeapRect.y, nonHeapRect.width, nonHeapRect.height);598599Color heapColor = greenBar;600Color nonHeapColor = greenBar;601602603for (PoolPlotter poolPlotter : poolPlotters) {604if (poolPlotter.threshold > 0L && poolPlotter.value > poolPlotter.threshold) {605if (poolPlotter.isHeap) {606heapColor = thresholdColor;607} else {608nonHeapColor = thresholdColor;609}610}611}612g.setColor(heapColor);613g.fillRect(heapRect.x + 1, heapRect.y + 1, heapRect.width - 1, heapRect.height - 1);614g.setColor(nonHeapColor);615g.fillRect(nonHeapRect.x + 1, nonHeapRect.y + 1, nonHeapRect.width - 1, nonHeapRect.height - 1);616617String str = Messages.HEAP;618int stringWidth = fm.stringWidth(str);619int x = heapRect.x + (heapRect.width - stringWidth) / 2;620int y = heapRect.y + heapRect.height - 6;621g.setColor(Color.white);622g.drawString(str, x-1, y-1);623g.drawString(str, x+1, y-1);624g.drawString(str, x-1, y+1);625g.drawString(str, x+1, y+1);626g.setColor(Color.black);627g.drawString(str, x, y);628629str = Messages.NON_HEAP;630stringWidth = fm.stringWidth(str);631x = nonHeapRect.x + (nonHeapRect.width - stringWidth) / 2;632y = nonHeapRect.y + nonHeapRect.height - 6;633g.setColor(Color.white);634g.drawString(str, x-1, y-1);635g.drawString(str, x+1, y-1);636g.drawString(str, x-1, y+1);637g.drawString(str, x+1, y+1);638g.setColor(Color.black);639g.drawString(str, x, y);640641// Highlight current plotter642g.setColor(Color.blue);643r = null;644Plotter plotter = (Plotter)plotterChoice.getSelectedItem();645if (plotter == heapPlotter) {646r = heapRect;647} else if (plotter == nonHeapPlotter) {648r = nonHeapRect;649} else if (plotter instanceof PoolPlotter) {650r = getBarRect((PoolPlotter)plotter);651}652if (r != null) {653g.drawRect(r.x - 1, r.y - 1, r.width + 2, r.height + 2);654}655}656657private Rectangle getBarRect(PoolPlotter poolPlotter) {658return new Rectangle(leftMargin + poolPlotter.barX,659height - bottomMargin - barHeight,660barWidth, barHeight);661}662663public Dimension getPreferredSize() {664return new Dimension(nonHeapRect.x + nonHeapRect.width + rightMargin,665height);666}667668public void mouseClicked(MouseEvent e) {669requestFocusInWindow();670Plotter plotter = getPlotter(e);671672if (plotter != null && plotter != plotterChoice.getSelectedItem()) {673plotterChoice.setSelectedItem(plotter);674repaint();675}676}677678public String getToolTipText(MouseEvent e) {679Plotter plotter = getPlotter(e);680681return (plotter != null) ? plotter.toString() : null;682}683684private Plotter getPlotter(MouseEvent e) {685Point p = e.getPoint();686Plotter plotter = null;687688if (heapRect.contains(p)) {689plotter = heapPlotter;690} else if (nonHeapRect.contains(p)) {691plotter = nonHeapPlotter;692} else {693for (PoolPlotter poolPlotter : poolPlotters) {694if (getBarRect(poolPlotter).contains(p)) {695plotter = poolPlotter;696break;697}698}699}700return plotter;701}702703public void mousePressed(MouseEvent e) {}704public void mouseReleased(MouseEvent e) {}705public void mouseEntered(MouseEvent e) {}706public void mouseExited(MouseEvent e) {}707708709public AccessibleContext getAccessibleContext() {710if (accessibleContext == null) {711accessibleContext = new AccessiblePoolChart();712}713return accessibleContext;714}715716protected class AccessiblePoolChart extends AccessibleJPanel {717public String getAccessibleName() {718String name = Messages.MEMORY_TAB_POOL_CHART_ACCESSIBLE_NAME;719720String keyValueList = "";721for (PoolPlotter poolPlotter : poolPlotters) {722String value = (poolPlotter.value * 100 / poolPlotter.max) + "%";723// Assume format string ends with newline724keyValueList +=725Resources.format(Messages.PLOTTER_ACCESSIBLE_NAME_KEY_AND_VALUE,726poolPlotter.toString(), value);727if (poolPlotter.threshold > 0L) {728String threshold =729(poolPlotter.threshold * 100 / poolPlotter.max) + "%";730if (poolPlotter.value > poolPlotter.threshold) {731keyValueList +=732Resources.format(Messages.MEMORY_TAB_POOL_CHART_ABOVE_THRESHOLD,733threshold);734} else {735keyValueList +=736Resources.format(Messages.MEMORY_TAB_POOL_CHART_BELOW_THRESHOLD,737threshold);738}739}740}741742return name + "\n" + keyValueList + ".";743}744}745}746747748OverviewPanel[] getOverviewPanels() {749if (overviewPanel == null) {750overviewPanel = new MemoryOverviewPanel();751}752return new OverviewPanel[] { overviewPanel };753}754755private static class MemoryOverviewPanel extends OverviewPanel {756MemoryOverviewPanel() {757super(Messages.HEAP_MEMORY_USAGE, usedKey, Messages.USED, Plotter.Unit.BYTES);758}759760private void updateMemoryInfo(long used, long committed, long max) {761getInfoLabel().setText(Resources.format(Messages.MEMORY_TAB_INFO_LABEL_FORMAT,762formatBytes(used, true),763formatBytes(committed, true),764formatBytes(max, true)));765}766}767}768769770