Memory issue on Android

#1

Hi,

I finally replaced my hybi00 python code with Autobahn, which was
really easy to do, and it's so much cleaner now. I'm only using the
websocket functionality for now, until I find a reasonable way to
upgrade to RPC without breaking anything (can't wait doing this, since
RPC on COM/ActiveX in Internet Explorer was such a pain back then).

My Android client has also been migrated to use the websocket code of
Autobahn.

First of all, when I tried to use the jar file by adding it to the
project, I got an error for then having multiple manifests. One which
I need for my project, and one which was in the jar file of Autobahn.
I didn't know how to solve this problem - I read about having to
recompile the library without the manifest included, but couldn't do
this myself. Maybe offering a version of the jar without the manifest
would be a handy thing to do, in case that this can be done. Or a
tutorial on how to use the jar file in an already existing project.
Anyhow, I solved this by copying the src tree of autobahn into my
project. Since I'm not using any RPC functionality at this point, I
removed the Autobahn*.java files.

Now to the problem:

I noticed that when my Android client lost the connection, either
because I disabled wifi or simply because it dropped, the client
crashed randomly, but more often than not, upon reconnection. After
spending some time looking at this issue, it turned out that there is
an issue with the garbage collection / memory management. I noticed
that the reader and the writer allocated 4mb each whenever a
connection got made. That's a lot of memory. If I disconnect, and the
garbage collector isn't fast enough to clean up the heap, a
reconnection attempt causes the app to request 8mb more, which leats
the app to be using 16mb. Stackoverflow "says" that 16 or 24 mb is the
max ammount of memory an app can allocate, so this is clearly the
issue here.

I lowered the ammount of the reader and the writer to 4k each, which
is more than enough to suit my needs, but this raises a question.

If websockets is supposed to be a streaming protocol, why allocate
such huge ammounts of memory? Is the RPC functionality of Autobahn
taking care of chopping up the transferred data into the size offered
by the reader/writer on the client and on the server? Or is the
generous buffersize just there to make enough memory for a RPC call
avaliable, and if a call receives a 5mb document as a response it just
throws an error? Because doing that would be a mistake.

I'm using the onTextMessage on the Android client, does the raw text
or binary "mode" handle this differently?

BTW: what's the difference between "text" and "raw text"? (just a
short answer, as I will be looking at the code anyway)

I'm liking this technology, a lot.

Kind regards,
Daniel

0 Likes

#2

Hi Daniel,

I finally replaced my hybi00 python code with Autobahn, which was
really easy to do, and it's so much cleaner now. I'm only using the
websocket functionality for now, until I find a reasonable way to
upgrade to RPC without breaking anything (can't wait doing this, since
RPC on COM/ActiveX in Internet Explorer was such a pain back then).

Nice to hear that it works for you / was easy ..

My Android client has also been migrated to use the websocket code of
Autobahn.

I'll get into the issues below, but a general comment: Autobahn
Android is definitely "alpha" still .. so yes, there are / will be
issues. Autobahn _Python_ is maturing and I would say getting past
"beta".

First of all, when I tried to use the jar file by adding it to the
project, I got an error for then having multiple manifests. One which
I need for my project, and one which was in the jar file of Autobahn.
I didn't know how to solve this problem - I read about having to
recompile the library without the manifest included, but couldn't do
this myself. Maybe offering a version of the jar without the manifest
would be a handy thing to do, in case that this can be done. Or a

Ok. I wasnt sure what needs to be in the JAR .. still learning there
also.
Ideally, a maven or whatever script could create the JAR automatically
(I did it via Eclipse), but I did not yet have time to figure that
out.

tutorial on how to use the jar file in an already existing project.
Anyhow, I solved this by copying the src tree of autobahn into my
project. Since I'm not using any RPC functionality at this point, I
removed the Autobahn*.java files.

Yeah, thats how I do that also .. and I'm currently not updating/
republishing the JAR often. So going with the code is - at this point
- better anyway.

Now to the problem:

I noticed that when my Android client lost the connection, either
because I disabled wifi or simply because it dropped, the client
crashed randomly, but more often than not, upon reconnection. After
spending some time looking at this issue, it turned out that there is
an issue with the garbage collection / memory management. I noticed
that the reader and the writer allocated 4mb each whenever a
connection got made. That's a lot of memory. If I disconnect, and the
garbage collector isn't fast enough to clean up the heap, a
reconnection attempt causes the app to request 8mb more, which leats
the app to be using 16mb. Stackoverflow "says" that 16 or 24 mb is the
max ammount of memory an app can allocate, so this is clearly the
issue here.

The reason it allocates that much is because I ran the Autobahn test
suite for Android, and the test suite drives an implemetation to
limits ..

Its not a good reason to have those large values as defaults though I
admit;)

I lowered the ammount of the reader and the writer to 4k each, which
is more than enough to suit my needs, but this raises a question.

Yep, usually its way too much ..

If websockets is supposed to be a streaming protocol, why allocate
such huge ammounts of memory? Is the RPC functionality of Autobahn

Well, there is a lot to say here, but only a few points:

WS per-se is frame-based .. but the (current) JS API is message based.

Autobahn Python is quite advanced impl. .. it offers message-based,
frame-based and fully streaming APIs (it can stream even the payload
of frames). I'm not aware of a lot WS impl. that do streaming i.e.
(and not many frame based also). AB Py also integrates with Twisted
Producers/Consumers for Flow-control (which you then need/want).

Currently, Autobahn Android is purely message based.

It would be relatively easy to allow frame-based API.

It's likely more involved to make it streaming. You need flow control.
And on Android, Autobahn uses NIO for networking, but nevertheless 2
background threads (for integration with UI message loops).

A third problem is RPC/PubSub, which uses Jackson (JSON processor).
That is capable of streaming for "normal" JSON processing, but it
might get tricky, because of the object mapping that Autobahn provides
(see my next mail).

The focus with AB Android is: first make RPC/PubSub easy/working. Then
see ..

taking care of chopping up the transferred data into the size offered
by the reader/writer on the client and on the server? Or is the
generous buffersize just there to make enough memory for a RPC call
avaliable, and if a call receives a 5mb document as a response it just
throws an error? Because doing that would be a mistake.

Its also a question of API: when you want the "convenience" of a
message based API, the implementation needs to buffer. When you don't
want to buffer large messages, you need some different API ..

I'm using the onTextMessage on the Android client, does the raw text
or binary "mode" handle this differently?

Its basically the same ..

BTW: what's the difference between "text" and "raw text"? (just a
short answer, as I will be looking at the code anyway)

Raw text doesnt convert into Java strings .. its pointless when you
want to feed a JSON processor like Jackson .. so its a performance
optimization.

I'm liking this technology, a lot.

Kind regards,
Daniel

Thanks for feedback. I'd be happy to discuss the stuff above
further .. esp. RPC/PubSub with Android UI apps ..

Cheers,
Tobias

0 Likes

#3

Hi Tobias,

ok, so if this is an Alpha version, I guess there's still a some room
to make slightly bigger changes.

If those 4mb per buffer are to push the tests to a limit, then it may
be that you're still missing a test. One which connects/disconnects as
often as possible in a loop, in order to take the behaviour of the
garbage collection into account.

Wouldn't it be better to move those buffers out of the reader/writer
classes into WebSocketConnection? There's no reason to discard the
buffers on a disconnect, but let the garbage collector release that
memory only if the entire WebSocketConnection instance get's released.
Maybe only recreate those buffers if the buffersize gets changed
explicitly duing a new connection.

Is it really necessary to use new readers/writers for each call to the
connect method? If not, then the buffers could stay where they are,
but the reader/writer would be created in the constructor of the
WebSocketConnection and stay alive for as long as an instance of it
exists.

Let me know what to think about this, or what you know about possible
problems of not discarding those reader/writers, so that I can start
working on this a bit without going into a different direction as the
one you would intend to go.

Kind regards,
Daniel

···

On Oct 21, 11:59 pm, tgo <tobias.o...@gmail.com> wrote:

Hi Daniel,

> I finally replaced my hybi00 python code with Autobahn, which was
> really easy to do, and it's so much cleaner now. I'm only using the
> websocket functionality for now, until I find a reasonable way to
> upgrade to RPC without breaking anything (can't wait doing this, since
> RPC on COM/ActiveX in Internet Explorer was such a pain back then).

Nice to hear that it works for you / was easy ..

> My Android client has also been migrated to use the websocket code of
> Autobahn.

I'll get into the issues below, but a general comment: Autobahn
Android is definitely "alpha" still .. so yes, there are / will be
issues. Autobahn _Python_ is maturing and I would say getting past
"beta".

> First of all, when I tried to use the jar file by adding it to the
> project, I got an error for then having multiple manifests. One which
> I need for my project, and one which was in the jar file of Autobahn.
> I didn't know how to solve this problem - I read about having to
> recompile the library without the manifest included, but couldn't do
> this myself. Maybe offering a version of the jar without the manifest
> would be a handy thing to do, in case that this can be done. Or a

Ok. I wasnt sure what needs to be in the JAR .. still learning there
also.
Ideally, a maven or whatever script could create the JAR automatically
(I did it via Eclipse), but I did not yet have time to figure that
out.

> tutorial on how to use the jar file in an already existing project.
> Anyhow, I solved this by copying the src tree of autobahn into my
> project. Since I'm not using any RPC functionality at this point, I
> removed the Autobahn*.java files.

Yeah, thats how I do that also .. and I'm currently not updating/
republishing the JAR often. So going with the code is - at this point
- better anyway.

> Now to the problem:

> I noticed that when my Android client lost the connection, either
> because I disabled wifi or simply because it dropped, the client
> crashed randomly, but more often than not, upon reconnection. After
> spending some time looking at this issue, it turned out that there is
> an issue with the garbage collection / memory management. I noticed
> that the reader and the writer allocated 4mb each whenever a
> connection got made. That's a lot of memory. If I disconnect, and the
> garbage collector isn't fast enough to clean up the heap, a
> reconnection attempt causes the app to request 8mb more, which leats
> the app to be using 16mb. Stackoverflow "says" that 16 or 24 mb is the
> max ammount of memory an app can allocate, so this is clearly the
> issue here.

The reason it allocates that much is because I ran the Autobahn test
suite for Android, and the test suite drives an implemetation to
limits ..

Its not a good reason to have those large values as defaults though I
admit;)

> I lowered the ammount of the reader and the writer to 4k each, which
> is more than enough to suit my needs, but this raises a question.

Yep, usually its way too much ..

> If websockets is supposed to be a streaming protocol, why allocate
> such huge ammounts of memory? Is the RPC functionality of Autobahn

Well, there is a lot to say here, but only a few points:

WS per-se is frame-based .. but the (current) JS API is message based.

Autobahn Python is quite advanced impl. .. it offers message-based,
frame-based and fully streaming APIs (it can stream even the payload
of frames). I'm not aware of a lot WS impl. that do streaming i.e.
(and not many frame based also). AB Py also integrates with Twisted
Producers/Consumers for Flow-control (which you then need/want).

Currently, Autobahn Android is purely message based.

It would be relatively easy to allow frame-based API.

It's likely more involved to make it streaming. You need flow control.
And on Android, Autobahn uses NIO for networking, but nevertheless 2
background threads (for integration with UI message loops).

A third problem is RPC/PubSub, which uses Jackson (JSON processor).
That is capable of streaming for "normal" JSON processing, but it
might get tricky, because of the object mapping that Autobahn provides
(see my next mail).

The focus with AB Android is: first make RPC/PubSub easy/working. Then
see ..

> taking care of chopping up the transferred data into the size offered
> by the reader/writer on the client and on the server? Or is the
> generous buffersize just there to make enough memory for a RPC call
> avaliable, and if a call receives a 5mb document as a response it just
> throws an error? Because doing that would be a mistake.

Its also a question of API: when you want the "convenience" of a
message based API, the implementation needs to buffer. When you don't
want to buffer large messages, you need some different API ..

> I'm using the onTextMessage on the Android client, does the raw text
> or binary "mode" handle this differently?

Its basically the same ..

> BTW: what's the difference between "text" and "raw text"? (just a
> short answer, as I will be looking at the code anyway)

Raw text doesnt convert into Java strings .. its pointless when you
want to feed a JSON processor like Jackson .. so its a performance
optimization.

> I'm liking this technology, a lot.

> Kind regards,
> Daniel

Thanks for feedback. I'd be happy to discuss the stuff above
further .. esp. RPC/PubSub with Android UI apps ..

Cheers,
Tobias

0 Likes

#4

Hi Daniel,

mass connect/disconnect test: a reasonable test .. though it might
require
some changes because of the interplay/orchestration between testee and
fuzzer. could you file an issue against Autobahn so we can track?

background buffers / threads allocation strategy: also a valid point
to think about. both could live throughout lifetime of
WebSocketConnection.
a user can still dispose resources by trashing WebSocketConnection.
could you file an issue against AutobahnAndroid?

Thanks!

···

On Oct 26, 5:52 am, "Daniel F." <sound...@gmail.com> wrote:

Hi Tobias,

ok, so if this is an Alpha version, I guess there's still a some room
to make slightly bigger changes.

If those 4mb per buffer are to push the tests to a limit, then it may
be that you're still missing a test. One which connects/disconnects as
often as possible in a loop, in order to take the behaviour of the
garbage collection into account.

Wouldn't it be better to move those buffers out of the reader/writer
classes into WebSocketConnection? There's no reason to discard the
buffers on a disconnect, but let the garbage collector release that
memory only if the entire WebSocketConnection instance get's released.
Maybe only recreate those buffers if the buffersize gets changed
explicitly duing a new connection.

Is it really necessary to use new readers/writers for each call to the
connect method? If not, then the buffers could stay where they are,
but the reader/writer would be created in the constructor of the
WebSocketConnection and stay alive for as long as an instance of it
exists.

Let me know what to think about this, or what you know about possible
problems of not discarding those reader/writers, so that I can start
working on this a bit without going into a different direction as the
one you would intend to go.

Kind regards,
Daniel

On Oct 21, 11:59 pm, tgo <tobias.o...@gmail.com> wrote:

> Hi Daniel,

> > I finally replaced my hybi00 python code with Autobahn, which was
> > really easy to do, and it's so much cleaner now. I'm only using the
> > websocket functionality for now, until I find a reasonable way to
> > upgrade to RPC without breaking anything (can't wait doing this, since
> > RPC on COM/ActiveX in Internet Explorer was such a pain back then).

> Nice to hear that it works for you / was easy ..

> > My Android client has also been migrated to use the websocket code of
> > Autobahn.

> I'll get into the issues below, but a general comment: Autobahn
> Android is definitely "alpha" still .. so yes, there are / will be
> issues. Autobahn _Python_ is maturing and I would say getting past
> "beta".

> > First of all, when I tried to use the jar file by adding it to the
> > project, I got an error for then having multiple manifests. One which
> > I need for my project, and one which was in the jar file of Autobahn.
> > I didn't know how to solve this problem - I read about having to
> > recompile the library without the manifest included, but couldn't do
> > this myself. Maybe offering a version of the jar without the manifest
> > would be a handy thing to do, in case that this can be done. Or a

> Ok. I wasnt sure what needs to be in the JAR .. still learning there
> also.
> Ideally, a maven or whatever script could create the JAR automatically
> (I did it via Eclipse), but I did not yet have time to figure that
> out.

> > tutorial on how to use the jar file in an already existing project.
> > Anyhow, I solved this by copying the src tree of autobahn into my
> > project. Since I'm not using any RPC functionality at this point, I
> > removed the Autobahn*.java files.

> Yeah, thats how I do that also .. and I'm currently not updating/
> republishing the JAR often. So going with the code is - at this point
> - better anyway.

> > Now to the problem:

> > I noticed that when my Android client lost the connection, either
> > because I disabled wifi or simply because it dropped, the client
> > crashed randomly, but more often than not, upon reconnection. After
> > spending some time looking at this issue, it turned out that there is
> > an issue with the garbage collection / memory management. I noticed
> > that the reader and the writer allocated 4mb each whenever a
> > connection got made. That's a lot of memory. If I disconnect, and the
> > garbage collector isn't fast enough to clean up the heap, a
> > reconnection attempt causes the app to request 8mb more, which leats
> > the app to be using 16mb. Stackoverflow "says" that 16 or 24 mb is the
> > max ammount of memory an app can allocate, so this is clearly the
> > issue here.

> The reason it allocates that much is because I ran the Autobahn test
> suite for Android, and the test suite drives an implemetation to
> limits ..

> Its not a good reason to have those large values as defaults though I
> admit;)

> > I lowered the ammount of the reader and the writer to 4k each, which
> > is more than enough to suit my needs, but this raises a question.

> Yep, usually its way too much ..

> > If websockets is supposed to be a streaming protocol, why allocate
> > such huge ammounts of memory? Is the RPC functionality of Autobahn

> Well, there is a lot to say here, but only a few points:

> WS per-se is frame-based .. but the (current) JS API is message based.

> Autobahn Python is quite advanced impl. .. it offers message-based,
> frame-based and fully streaming APIs (it can stream even the payload
> of frames). I'm not aware of a lot WS impl. that do streaming i.e.
> (and not many frame based also). AB Py also integrates with Twisted
> Producers/Consumers for Flow-control (which you then need/want).

> Currently, Autobahn Android is purely message based.

> It would be relatively easy to allow frame-based API.

> It's likely more involved to make it streaming. You need flow control.
> And on Android, Autobahn uses NIO for networking, but nevertheless 2
> background threads (for integration with UI message loops).

> A third problem is RPC/PubSub, which uses Jackson (JSON processor).
> That is capable of streaming for "normal" JSON processing, but it
> might get tricky, because of the object mapping that Autobahn provides
> (see my next mail).

> The focus with AB Android is: first make RPC/PubSub easy/working. Then
> see ..

> > taking care of chopping up the transferred data into the size offered
> > by the reader/writer on the client and on the server? Or is the
> > generous buffersize just there to make enough memory for a RPC call
> > avaliable, and if a call receives a 5mb document as a response it just
> > throws an error? Because doing that would be a mistake.

> Its also a question of API: when you want the "convenience" of a
> message based API, the implementation needs to buffer. When you don't
> want to buffer large messages, you need some different API ..

> > I'm using the onTextMessage on the Android client, does the raw text
> > or binary "mode" handle this differently?

> Its basically the same ..

> > BTW: what's the difference between "text" and "raw text"? (just a
> > short answer, as I will be looking at the code anyway)

> Raw text doesnt convert into Java strings .. its pointless when you
> want to feed a JSON processor like Jackson .. so its a performance
> optimization.

> > I'm liking this technology, a lot.

> > Kind regards,
> > Daniel

> Thanks for feedback. I'd be happy to discuss the stuff above
> further .. esp. RPC/PubSub with Android UI apps ..

> Cheers,
> Tobias

0 Likes