OutOfMemoryError at PacketWriter.writePackets()

Hey everyone. Anyone ever see anything like this?

com.example.com.MyServerPeerMain at localhost:3264

Thread (Running)

Thread (Running)

Thread (Running)

Thread (Running)

Thread (Running)

Thread (Running)

Thread (Running)

Thread (Running)

Thread (Suspended (exception OutOfMemoryError))

PacketWriter.writePackets() line: 205

PacketWriter.access$000(PacketWriter) line: 34

PacketWriter$1.run() line: 59

Thread (Running)

Thread (Running)

Thread (Running)

Thread (Suspended (exception OutOfMemoryError))

MyPollerThread.run() line: 138

Thread.run() line: not available

/code

So here’'s the setup of my application:

There are two parts, each running in its own thread using the same JVM:

  1. data provider user, which accepts IQ GET packets and sends IQ RESULTs.

  2. data distributor user, which sends IQ GET packets to the data provider user and posts the data from the IQ RESULTs to a MultiUserChat every two seconds.

I profiled this and noticed that Message objects that come from the MUC to the “My Poller Thread” are not being GC’'d. And after a while, this will bring the application down (I have more than a hundred properties in each Message).

After stepping through the Smack source, I noticed that some of the packet collectors in PacketReader have massive amounts (e.g., hundreds) of Message objects after a while.

I don’‘t believe I’‘ve created these packet collectors, so I don’'t know how to cancel them. Any one have any ideas? Should I send more details?

I appreciate the help anyone can give.

Why, yes, I am[/b] replying to my own question. I think I’'ve found the reason:

According MultiUserChat.init(), a packet collector is created automatically for messages destined for your MUC, even if you never intend on handling those messages:

private void init() {

// Create a collector for incoming messages.

messageFilter =

new AndFilter(

new FromMatchesFilter(room),

new MessageTypeFilter(Message.Type.GROUP_CHAT));

messageFilter = new AndFilter(messageFilter, new PacketFilter() {

public boolean accept(Packet packet) {

Message msg = (Message) packet;

return msg.getBody() != null;

}

});

messageCollector = connection.createPacketCollector(messageFilter);

/code

Needless to say, the packet collector will keep collecting packets destined to the MUC you created, even if you never want to see them. In my case, a large Message gets sent to the MUC every two seconds, so eventually I run out of memory.

Anyone have the same train of thought I do? Any other ideas? All are appreciated, thanks.

You make a good point. I for one use the Message Listener in muc, which itself creates a seperate packet collector. There should be a way to disable these collectors.

You make a good point. I for one use the Message

Listener in muc, which itself creates a seperate

packet collector. There should be a way to disable

these collectors.

Yes, needless to say, I agree wholeheartedly :). I hope it becomes an official Smack issue. Is there a real need to accumulate all Message objects like that? Through my limited viewpoint, no, but I might very well not be seeing the entire picture. IMHO, the Message packet collector should only be instantiated when the user adds a Message listener.

Listeners for presence and subject updates are also automatically created.

P.S. I’'ll be more than happy to write a patch to create the message listener only when a message listener is registered (if ever). Is this something you guys would be interested in?

Well, I’'ve found a workaround.

Just as a summary to those who haven’‘t been following the thread, I had a MultiUserChat object sending Message’‘s to the MUC every two seconds. It didn’'t listen on the MUC or anything like that; just sent a new message to it every two seconds.

The workaround for me is rather simple: just receive the next Message coming into the MUC right after it sent its Message. Barring some weird filtering, network issues, or a more active MUC, it’'ll work:

this.muc = new MultiUserChat(this.xmppConnection, “irrelevant”);

this.muc.join(“irrelevant”);

this.muc.sendMessage(outgoingMessage);

// remove memory leak by just getting the next message and doing nothing with it

this.muc.nextMessage();

/code

This will work when there is only user sending to the MUC (which is what’'s happening in our application). This workaround removed the need to hack the Smack source to get around this issue.