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

Reply via email to