In one of his tips he mentions the following:
CharArrayBuffer: Developers are regularly using the
getString()method on the
Cursor. Unfortunately, it implies creating
Stringobjects. These objects are likely to be garbaged once the user starts scrolling. In order to prevent object creation and consequently garbage collection freezes, it is possible to use a
CharArrayBufferthat consists on copying data from the
Cursorto a raw array of
charthat will be directly used by our
TextViews. Instead of having to create a
Stringobject, we will hence reuse a
My first thought was: Oh my! I am using getString() everywhere! We had some performance issues in the past with a Gallery so it was a great place to start fixing the code.
Yesterday evening I modified the adapter's code to use CharArrayBuffer instead of getString(). When I tested the app it felt slower than before and very blocky. I went to sleep.
Today evening I decided starting from the scratch, but instead of using my app I decided to create a toy app. I stole some code from @vogella and start testing.
You can download the app from this link.
My first test was with the traceview tool:
In the screenshot you see two instances of the traceview tool analyzing the bindView method.
Over the top, you can seewithoutFix.trace (the one using the cursor.getString() method) and below the withFix.trace (which is using the cursor.copyStringToBuffer).
Another thing I took some time trying to understand is this:
Conclusions so far:
* Using cursor.copyStringToBuffer() seems to run the bindView method faster than cursor.getString().
* cursor.getString() is faster than cursor.copyStringToBuffer()
The difference is not much so I wouldn't take care of keeping the fix. The code looks clearer with the getString() method.
But wait, let's give it a try to the Memory Analyzer (MAT).
Note: After hearing @dubroy's talk at the googleIO 2011 I wanted to do something like this :)
@dubroy also wrote an article for the Android Developers blog called "Memory Analysis for Android".
What I did was comparing two heaps from both options.
Objects #0 and Shallow Heap #0 are for the cursor.getString() version and
Objects #1 and Shallow Heap #1 are for the cursor.copyStringToBuffer().
Not much to say here.
* The getString() versions has less String objects.
* The copyStringToBuffer uses more heap. (I use three new CharArrayBuffer(128))
I am not an expert using this tools but, from what I have tested, I couldn't notice a performance improvement when using cursor.copyStringToBuffer().
What do you guys think?
I had the following conversation with cyrilmottier over twitter:
cyrilmottier: The actual benefit is you will reduce garbage collection to a minimum. This is less useful in Android 2.3 or higher.
2.3 introduced a generational GC. Hence, CharArrayBuffer is probably more useful on old Android versions.
me: It makes sense. I will keep the getString() calls, knowing that I have the buffer if I need to improve memory usage.