Hi Piero,
On 1/23/07, PieroPositivo <[EMAIL PROTECTED]> wrote:
Hello,
I have created a very simple echo server that broadcasts messages to all
connected clients.
I have one main class and an EchoHandler class that extends
IoHandlerAdapter
I tested the server with an application that creates simulated clients
sending a short text message and I was surprised to see a very high cpu
utilization even with a small amount of users connected (75-100)
The test machine is an Intel Core Duo 2gh MacBook PRO.
When the test reaches 250-300 users the server sucks all the cpu and it
also
consumes a lot of memory until a java.lang.OutOfMemoryError crashes the
JVM
The server code is so simple that I really can't see any problem. Plus I
am
not holding references to objects that are never destroyed. I didn't have
the time to check the code running with a profiler but I think that the
problems could be related with the pooled ByteBuffers.
This is the code used to broadcast the messages:
ByteBuffer rb = ( ByteBuffer ) message;
byte[] byteData = new byte[rb.remaining()];
rb.get(byteData);
ByteBuffer wb;
synchronized (sessions)
{
Iterator it = sessions.iterator();
while(it.hasNext())
{
IoSession s = (IoSession) it.next();
// Write the received data back to remote peer
wb = ByteBuffer.allocate( byteData.length );
wb.put( byteData );
wb.flip();
s.write( wb );
}
}
The loop code is taken from the Chat example. What I don't like is that in
the loop the wb buffer is allocated as new all the times (well, maybe it
is
taken from the pool?). I tried reusing the same Buffer object, but it
complains since it's already been released. I also tried setting the
"pooled" property to false, in order to reuse it, but I received the same
error when I called the clear() method on the buffer
Any advices? Should i configure the pool differently?
Is there a way I can bypass the ByteBuffer pool?
First, you don't need to allocate a ByteBuffer to broadcast messages
anymore. You can just duplicate it by calling 'duplicate()' method.
Assuming byteData is a ByteBuffer... (if not, you can always wrap it by
calling ByteBuffer.wrap(...).)
synchronized (sessions)
{
Iterator it = sessions.iterator();
while(it.hasNext())
{
IoSession s = (IoSession) it.next();
// Write the received data back to remote peer
s.write( byteData.duplicate() );
}
}
This will reduce the amount of memory used significantly.
To bypass buffer pooling, use the following code in the begining of your
application:
ByteBuffer.setAllocator(new SimpleByteBufferAllocator()); // Disables
pooling.
ByteBuffer.setUseDirectBuffers(false); // Direct buffers perform bad.
Please let us know how the result differs.
HTH,
Trustin
--
what we call human nature is actually human habit
--
http://gleamynode.net/
--
PGP key fingerprints:
* E167 E6AF E73A CBCE EE41 4A29 544D DE48 FE95 4E7E
* B693 628E 6047 4F8F CFA4 455E 1C62 A7DC 0255 ECA6