I am using the method fromJson( Reader reader, Type t) on a static
Gson object in android application.
I have a service that runs in the background and that will contact a
webservice every minute. This webservice returns a Json inputstream
from which I will create an InputStreamReader that I will pass on to
the fromJson method of my Gson static instance.
However after doing a memory dump of my application after several
minutes have passed, I can see a steadily increase in
com.google.gson.stream.JsonReader objects that can't seem to be
garbage collected.
I have ran several tests and each time the Eclipse Memory Analyzer
notifies me of a possible leak, all instances of JsonReader classes.
The following is an excerpt of the Eclipse Memory Analyzer output:
63 instances of "com.google.gson.stream.JsonReader", loaded by
"dalvik.system.PathClassLoader @ 0x452e61f0" occupy 12,820,880
(83.22%) bytes.
Biggest instances:
•com.google.gson.stream.JsonReader @ 0x45395cc8 - 213,144 (1.38%)
bytes.
•com.google.gson.stream.JsonReader @ 0x4539f8c8 - 213,144 (1.38%)
bytes.
•com.google.gson.stream.JsonReader @ 0x453ce468 - 213,144 (1.38%)
bytes.
...
So in this above case, my webservice method has been called 63 times,
and each time the Json result stream was passed to a static Gson
instance that uses the fromJson method with the reader and type
parameter.
Each time a 208kb instance can't seem to be garbage collected. However
the memory analyzer can't seem to pin down the GC root that keeps them
in memory.
Can somebody guide me in the right direction on how to tackle this
problem.
Is it a problem with my code that is preventing the JsonReader
instances from being garbage collected or is there something in the
gson library that keeps them around ?
I'm new to memory analysis so go easy on me ;)
But yes, eventually I get an OutOfMemory exception.
Thanks,
Harm
The output came from an Android heap dump analyzed with the Eclipse
memory analyzer.
However, I did some more testing with the following code,
I hope the formatting doesn't mess it up.
Basically, I created a loop that called my webservice 200 times.
for(int i = 0; i < 200; i++)
{
InputStream stream = task.performRequestAndReturnStream(message, url,
context);
InputStreamReader reader = new InputStreamReader(stream);
items = (LogisticsCollection[])
JsonUtils.getJsonLogisticsCollection(reader);
stream.close();
reader.close();
reader = null;
stream = null;
}
In the method JsonUtils.getJsonLogisticsCollection I use a Gson object
and call fromJson passing the InputStreamReader. After the Gson object
has parsed the stream, I set it explicitly to null so it can be
garbage collected.
Here is the method from the JsonUtils class:
public static Object getJsonLogisticsCollection(Reader reader) {
Gson gson = GetGsonParser();
Type type= new
TypeToken<DotNetWebserviceData<LogisticsCollection[]>>() {}.getType();
DotNetWebserviceData<LogisticsCollection[]> data =
(DotNetWebserviceData<LogisticsCollection[]>)gson.fromJson(reader,
type);
gson = null;
return data.d;
}
Now here is the strange part, if I run this loop, after a while it
will get an out of memory exception and the heap dump shows tons of
JsonReader objects that can't get garbage collected.
But if I create a JsonReader object myself and pass that to my
JsonUtils method (after changing its signature to accept a JsonReader
instead of a Reader object), then all is fine and I get no leaks and
the loop finishes without problems.
for(int i = 0; i < 200; i++)
{
InputStream stream = task.performRequestAndReturnStream(message, url,
context);
JsonReader reader = new JsonReader( new InputStreamReader(stream));
items = (LogisticsCollection[])
JsonUtils.getJsonLogisticsCollection(reader);
stream.close();
reader.close();
reader = null;
stream = null;
}
When I dump the heap after executing this second loop, there are no
traces of JsonReader objects to be found.
So, this leads me to believe my code is fine and something in the gson
library prevents the JsonReaders from being garbage collected when a
Reader object is being passed.
Harm
Thanks
Harm