package games.strategy.triplea.ui; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.lang.ref.WeakReference; import java.text.DecimalFormat; import javax.swing.JLabel; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import games.strategy.ui.SwingAction; import games.strategy.util.ThreadUtil; public class MemoryLabel extends JLabel { private static final long serialVersionUID = -6011470050936617333L; public MemoryLabel() { update(); addMouseListener(new MouseAdapter() { @Override public void mouseReleased(final MouseEvent e) { if (e.isPopupTrigger()) { gc(e); } } @Override public void mousePressed(final MouseEvent e) { if (e.isPopupTrigger()) { gc(e); } } }); final Thread t = new Thread(new Updater(this), "Memory Label Updater"); t.start(); } protected void gc(final MouseEvent e) { final JPopupMenu menu = new JPopupMenu(); menu.add(SwingAction.of("Garbage Collect", event -> { System.gc(); System.runFinalization(); System.gc(); System.runFinalization(); System.gc(); })); menu.show(this, e.getX(), e.getY()); } public void update() { final long free = Runtime.getRuntime().freeMemory(); final long total = Runtime.getRuntime().totalMemory(); final long used = total - free; final DecimalFormat format = new DecimalFormat("###.##"); setText(format.format(used / 1000000.0) + "/" + format.format(total / 1000000.0) + " MB"); } } /** * This thread will stop when the label is garbage collected. */ class Updater implements Runnable { private final WeakReference<MemoryLabel> m_label; Updater(final MemoryLabel label) { m_label = new WeakReference<>(label); } @Override public void run() { while (m_label.get() != null) { if (!ThreadUtil.sleep(2000)) { return; } update(); } } private void update() { SwingUtilities.invokeLater(() -> { final MemoryLabel label = m_label.get(); if (label == null || !label.isVisible()) { return; } label.update(); }); } }