Class Size

Are you concerned about the memory your java application uses?

You probably have already removed those unused methods or fields or variables, you have used an integer field to store flags instead of using booleans, you have changed an algorithm to not use an intermediate ArrayList, …

There is one area that is usually overlooked when writing an application which is the size of classes. Once a class is loaded in memory, it will stay in memory until your program terminates and classes have a memory price tag that should not be ignored.

To determine the cost of a class, I wrote a small application that generates thousands of similar classes plus one that calls them all.
The generated application first waits for the user to press ENTER in the console. This gives you the time to look at the process in the Task Manager and write down the memory size of the process.
Once you press ENTER, the application invokes 10.000 classes and then pauses again. Go back to the Task Manager, record the new memory size and do the maths.

Here is an example of a generated class:

package generated.p4;
public class C2017 {
    private String a;
    public void setA(String a) {
        this.a = a;
    }
    public String getA() {
        return a;
    }
    public static void foo(){
        final C2017 a = new C2017();
        a.setA(a.getA());
    }
}

Depending on the VM you choose to run the application, the memory consumed by each class varies betweeen 2Kb (-client) and 1.7Kb (-server).

Listener Pattern

Knowing that any class will cost approximatively 2Kb, you may want to revisit some of the patterns you use when writing code.
A typical example is the dialog listeners.
If you usually write code like this:

public class MyDialog {

    private void init(){
        JButton addButton = new JButton("Add...");
        addButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                whenAdd();
            }
        });
        JButton removeButton = new JButton("Remove...");
        removeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                whenRemove();
            }
        });
        JList list = new JList();
        list.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                whenSelectionChanges();
            }
        });
    }

    private void whenAdd() {
    }

    private void whenRemove() {
    }

    private void whenSelectionChanges() {
    }
}

You may want to switch to a pattern that only uses one listener:

public class MyDialog {
    private JButton addButton;
    private JButton removeButton;
    private JList list;
    private Listener listener = new Listener();

    public BetterDialog(){
        addButton = new JButton("Add...");
        addButton.addActionListener(listener);
        removeButton = new JButton("Remove...");
        removeButton.addActionListener(listener);
        list = new JList();
        list.addListSelectionListener(listener);
    }

    private void whenAdd() {
    }

    private void whenRemove() {
    }

    private void whenSelectionChanges() {
    }

    class Listener implements ActionListener, ListSelectionListener {

        public void actionPerformed(ActionEvent e) {
            Object source = e.getSource();
            if (source == addButton) {
                whenAdd();
            }else if (source == removeButton) {
                whenRemove();
            }
        }

        public void valueChanged(ListSelectionEvent e) {
            Object source = e.getSource();
            if (source == list) {
                whenSelectionChanges();
            }
        }
    }
}

The revisited version may look less efficient because the code is a bit longer and the widget are stored in fields but in reality this version uses 2 classes instead of 4 and will therefore save about 4Kb of memory, the resulting byte code is smaller by about 10% and even the small memory overhead to store the widgets will eventually be reclaimed by the garbage collector.

Comments are closed.