'Why Android Studio profiler heap dump showing about 7x overhead for an arraylist?

I was wondering and testing object's memory allocation on Android/Java and found something strange happening on heap, well maybe it's just normal.

Here is what i did and found; there is a txt data file that 850kb in file size with 26220 lines, 30 chars per line. I get all lines via inputstream and add them to an arraylist. Then i dump heap on Android Studio profiler and as you can see on screenshot, heap dump looks like counting all related objects separately and adding them all making 7x larger memory size than actual text data. Normally app heap's total retained size is 2.8MB before, after creating the arraylist it gets about 9MB, so it makes 6.2MB memory size for a 0.85MB text data. Is this behavior completely normal in Android/Java or something wrong with profiler?
Thanks all in advance.

profiler heap screenshot

UPDATE

I took another screenshot this time from Android Studio's memory profiler histogram not from heap dump. It's interesting it's showing memory consumption as expected or at least not abnormal on this histogram unlike misleading/confusing heap dump. As you can see on the screenshot, before creating arraylist, total consumed memory by application is 34.5MB and Java memory (supposed to be heap) is 5.2MB. After creating the arraylist from 850KB raw text file, total memory becomes 37MB and Java 7.1MB making 2.5MB total memory and 1.9MB heap memory difference.

It seems like retained size information on Android Studio's heap dump is misleading and should be ignored as suggested by Andreas.

screenshot 2



Solution 1:[1]

You're reading it wrong.

Why they summed the "Retained Size" is beyond me, because it's an entirely useless value.

In this case, we have an ArrayList<String> with 26220 String objects:

  • That means we have 1 ArrayList, so only 1 of those 525 allocations is ours. The shallow size is shallow(ArrayList) = 10500 / 525 = 20 bytes.

  • An ArrayList references an Object[], so only 1 of those 661 allocations is ours. The shallow size depends on the array size, but lets say it is 16 bytes overhead + 4 bytes per element, so shallow(Object[]) = 16 + 4 * 26220 = 104896 bytes.

  • The array elements reference 26220 String objects, so 26220 of those 39896 allocations belong to us. The shallow size is 638336 / 39896 = 16 bytes per String, so shallow(String) = 26220 * 16 = 419520 bytes.

  • String references a byte[] so 26220 of those 40407 allocations belong to us. The shallow size depends on the array size, but lets go with the average size of 30 characters per line, i.e. 30 bytes per array, which means it is 16 bytes overhead + 30 bytes = 46 bytes, rounded up to multiple of 8 means 48 bytes, so 48 * 26220 = 1258560 bytes. Don't know why it only shows 965588 bytes, but lets just go with that, so shallow(byte[]) = 965588 bytes.

The Retained Size is the Shallow Size + the Retained Size of anything referenced:

retained(byte[]) = shallow(byte[]) // byte[] doesn't reference anything
                 = 965588 bytes

retained(String) = shallow(String) + retained(byte[])
                 = shallow(String) + shallow(byte[])
                 = 419520 + 965588 = 1385108 bytes

retained(Object[]) = shallow(Object[]) + retained(String)
                   = shallow(Object[]) + shallow(String) + shallow(byte[])
                   = 104896 + 419520 + 965588 = 1490004 bytes

retained(ArrayList) = shallow(ArrayList) + retained(Object[])
                    = shallow(ArrayList) + shallow(Object[]) + shallow(String) + shallow(byte[])
                    = 20 + 104896 + 419520 + 965588 = 1490024 bytes

Now, the summed "Retained Size" is ludicrous because if we sum those 4 values, we end up counting the 965588 bytes of the byte[] 4 times, getting 965588 + 1385108 + 1490004 + 1490024 = 5330724 bytes, and that's just not of any use. Please ignore the summed "Retained Size" value as it is entirely meaningless.

The ArrayList uses 1490024 bytes of memory, not 6.2MB.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Andreas