I recently started playing with tools like MAT and also reading up about memory usage, performance (tuning) etc.
One of the interesting blog posts I came by was a comparison of JVM versions, that mentions that in 7u40, the default on how the JVM allocates the backing memory for ArrayList and HashMap has changed.
When you do
List<Foo> bla = new ArrayList<Foo>();
the VM will allocate memory for the base object and in vm versions prior to 7u40 also 10* 4bytes for the references to
Foo objects, which (with alignment and so on) accounts to 80 bytes per empty
In 7u40, the array for the references is no longer eagerly allocated so that an empty
ArrayList now only occupies the base 24 bytes, which account for 56bytes saving.
You may say so what, that are only 56 bytes, but remember that memory not allocated does not fill the heap, does not need to be garbage collected and also does not require memory bandwidth for the initial nulling out.
And so often an empty list/map does not come alone as in a case like this (output from MAT):
With 225k empty
ArrayLists, 56 bytes matter: 225k*56 bytes are 12 MB that you would save just by switching from a JVM pre 7u40 to 7u40 or later without a code change (of course not allocating those lists at all would save even more).
The situation for
HashMap is similar: before 7u40 an empty one uses 136 bytes while in 7u40+ is uses 48, a saving of 88 bytes per empty HashMap or with the 235k empty HashMaps of the above example a saving of 20 MB.
Another (older) change is that in 7u06 the minimum size of String objects also has been reduced by 8 bytes, which matters a lot if you have millions of Strings in your VM.
Of course (as I've mentioned already) if you have access to the source code and can prevent the allocation of those empty objects altogether you would save even more memory.