Ogni applicazione Java ha associata un istanza della classe Runtime che può essere utilizzata per vari motivi. Uno di questi è controllare lo stato della memoria.

I metodi che ci interessano sono tre:

public long freeMemory()
public long maxMemory()
public long totalMemory()

Il primo metodo indica la memoria libera per l’applicazione, il secondo indica la memoria totale disponibile nella virtual machine mentre il terzo indica l’ammontare massimo di memoria che la virtual machine proverà ad usare.

Quello che segue è un semplice monitor della memoria. Ogni mezzo secondo un thread raccoglie le informazioni e le mostra in una label di un frame. Per aggiungere un tocco di dinamicità, creeremo ad ogni step 10.000 stringhe pseudo-random e le aggiungeremo ad una lista. Vedremo quindi la memoria libera diminuire di volta in volta e aumentare la memoria massima disponibile per la virtual machine.

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.UUID;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class MemoryMonitor extends JFrame {
  private static final long serialVersionUID = -115538958099100707L;
  private static final String[] UNITS = {"B", "KB", "MB", "GB"};
  private static final DecimalFormat formatter = new DecimalFormat("###,###.##");
  private static final Runtime runtime = Runtime.getRuntime();
  //
  private JLabel label;
  private ArrayList<String> list = new ArrayList<String>();

  class RefreshThread extends Thread {
    public void run() {
      try {
        while(true) {
          Thread.sleep(500);
          for(int i = 0; i < 10000; i++) {
              list.add(UUID.randomUUID().toString());
            }
          System.out.println("Items: " + list.size());
          SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
              MemoryMonitor.this.refresh();
            }
          });
        }
      } catch(Throwable th) {
        th.printStackTrace();
      }
    }
  }

  public MemoryMonitor() {
    super("MemoryMonitor");

    label = new JLabel();
    getContentPane().add(label);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(400, 350, 400, 60);
    setResizable(false);
    refresh();
    startRefreshThread();
  }

  private void startRefreshThread() {
    new RefreshThread().start();
  }

  private void refresh() {
    String maxMem = formatBytes(runtime.maxMemory());
    String freeMem = formatBytes(runtime.freeMemory());
    String totMem = formatBytes(runtime.totalMemory());

    label.setText(freeMem + "/" + totMem + " - Max memory: " + maxMem);
  }

  public String formatBytes(long val) {
    String valStr = String.valueOf(val);
    String unit = UNITS[0];
    int unitIdx = 0;
    double dval = val;
    //
    while(dval >= 1024.0 && unitIdx < UNITS.length) {
     dval /= 1024;
     unit = UNITS[++unitIdx];
     valStr = String.valueOf(dval);
    }
    //
    return formatNumber(valStr) + " " + unit;
  }

  private synchronized String formatNumber(String str) {
    return formatter.format(Double.parseDouble(str));
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        new MemoryMonitor().setVisible(true);
      }
    });
  }
}

Uno screen dell’applicazione: