You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mina.apache.org by Trustin Lee <tr...@gmail.com> on 2007/01/22 04:04:23 UTC
Re: OutOfMemory when using ReadThrottleFilter
Hi Swen,
On 1/4/07, Swen Moczarski <ma...@swenmoc.de> wrote:
>
> Hi, I have done some performance tests. A client is sending a lot of small
> messages over a connection to a server. In
> spite of the read-throttle-filter (
> org.apache.mina.filter.ReadThrottleFilterBuilder) the server will be
> overloaded and I
> get out-of-memory exceptions.
>
> Before the message will be forwarded to the ExecutionFilter, the
> ReadThrottleFilter makes use of ByteBuffer.remaining()
> for increasing the calculated size of the connection buffer. But after
> passing the ExecutionFilter the method
> ByteBuffer.capacity() is used to decrease the size. Is that behaviour
> intended?
>
> When I'm patching the ReadThrottleFilterBuilder to use ByteBuffer.capacity()
> for both cases the performance test works
> absolutely fine, there are no longer out-of-memory exceptions. BTW, in the
> SVN-history I have seen that the first
> version uses ByteBuffer.capacity() for both cases.
It seems like there was a mistake. Could you try to change both capacity()
calls to remaining()? I think it's a correct fix than using capacity().
I have a second question: Is it correct that for a SocketAcceptor the
> ReadThrottleFilter have to add in the session
> created method like this:
>
> public void sessionCreated(IoSession session) throws Exception {
> ReadThrottleFilterBuilder builder = new ReadThrottleFilterBuilder();
> builder.attach(session.getFilterChain());
> }
>
> This is the first time where the ExecutionFilter is available in the
> filter chain.
Yes, looks fine to me.
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
Re: OutOfMemory when using ReadThrottleFilter
Posted by Paul Chen <ch...@gmail.com>.
The root cause of this problem is running out of Java heap memory, when
don't
we use a more direct approach by checking the real remaining heap in the
filter?
Runtime.getRuntime().freeMemory();
It is hard to prevent the problem completely by tracking byte buffers.
Best Regards
On 1/30/07, Swen Moczarski <ma...@swenmoc.de> wrote:
>
> Hi Trustin,
>
> thanks a lot for your response.
>
> Trustin Lee wrote:
> > Hi Swen,
> >
> > On 1/4/07, Swen Moczarski <ma...@swenmoc.de> wrote:
> >>
> >> Hi, I have done some performance tests. A client is sending a lot of
> >> small
> >> messages over a connection to a server. In
> >> spite of the read-throttle-filter (
> >> org.apache.mina.filter.ReadThrottleFilterBuilder) the server will be
> >> overloaded and I
> >> get out-of-memory exceptions.
> >>
> >> Before the message will be forwarded to the ExecutionFilter, the
> >> ReadThrottleFilter makes use of ByteBuffer.remaining()
> >> for increasing the calculated size of the connection buffer. But after
> >> passing the ExecutionFilter the method
> >> ByteBuffer.capacity() is used to decrease the size. Is that behaviour
> >> intended?
> >>
> >> When I'm patching the ReadThrottleFilterBuilder to use
> >> ByteBuffer.capacity()
> >> for both cases the performance test works
> >> absolutely fine, there are no longer out-of-memory exceptions. BTW, in
> >> the
> >> SVN-history I have seen that the first
> >> version uses ByteBuffer.capacity() for both cases.
> >
> >
> > It seems like there was a mistake. Could you try to change both
> capacity()
> > calls to remaining()? I think it's a correct fix than using capacity().
> >
>
> When I'm using the remaining() calls, I still get an out-of-memory error.
> But when I'm using capacity() it looks ok.
> Maybe, this becomes only a problem when a lot of small messages are stored
> in bigger ByteBuffers. But I think it would
> be safer to prevent overloading when the ReadThrottleFilter tracks the
> memory allocated by the ByteBuffers (capacity())
> instead of the received bytes. WDYT?
>
> Here is my simple stess-test:
>
> public class Test {
>
> private final static int PORT = 8056;
>
> public static void main(String[] args) throws Exception {
> IoHandler handler = new IoHandlerAdapter() {
>
> public void exceptionCaught(IoSession session, Throwable cause)
> throws Exception {
> cause.printStackTrace();
> }
> public void sessionCreated(IoSession session) throws Exception {
> ReadThrottleFilterBuilder throttleFilter = new
> ReadThrottleFilterBuilder();
> throttleFilter.attach(session.getFilterChain());
> }
> };
> SocketAcceptor acceptor = new SocketAcceptor();
> acceptor.bind(new InetSocketAddress(PORT), handler);
>
> Socket socket = new Socket("localhost", PORT);
> Writer writer = new OutputStreamWriter(socket.getOutputStream());
>
> while (true) {
> writer.write("test");
> writer.flush();
> }
> }
> }
>
> I have tried the test with version 1.0.1 and the current trunk (with the
> current trunk it takes longer until the memory
> error occures).
> Should I attach the test to
> https://issues.apache.org/jira/browse/DIRMINA-338 and reopen the issue?
>
>
> Regards,
> Swen
>
>
Re: OutOfMemory when using ReadThrottleFilter
Posted by Trustin Lee <tr...@gmail.com>.
Hi Swen,
On 1/31/07, Swen Moczarski <ma...@swenmoc.de> wrote:
>
> Hi Trustin,
>
> thanks a lot for your response.
>
> When I'm using the remaining() calls, I still get an out-of-memory error.
> But when I'm using capacity() it looks ok.
> Maybe, this becomes only a problem when a lot of small messages are stored
> in bigger ByteBuffers. But I think it would
> be safer to prevent overloading when the ReadThrottleFilter tracks the
> memory allocated by the ByteBuffers (capacity())
> instead of the received bytes. WDYT?
The root cause of this problem is that the default receive buffer size is
too big for smaller sockets. MINA allocates a buffer whose size is same
with the default receive buffer size because it doesn't know how large chunk
of data will come in. I didn't thought the default receive buffer size is
big, but it is turned out to be bigger than 40k. This means you allocate
40k buffer even if the size of the packet you exchange is much smaller than
that. In this case, using remaining() might cause unexpected
OutOfMemoryError. Configuring the size of the receive buffer with the
following code will do the trick:
((SocketSessionConfig) acceptor.getDefaultConfig
().getSessionConfig()).setReceiveBufferSize(512);
If we replace remaining() with capacity(), we won't need to do that, but we
will observe unexpected slowdown in low throughput communication.
Here is my simple stess-test:
>
> public class Test {
>
> private final static int PORT = 8056;
>
> public static void main(String[] args) throws Exception {
> IoHandler handler = new IoHandlerAdapter() {
>
> public void exceptionCaught(IoSession session, Throwable cause)
> throws Exception {
> cause.printStackTrace();
> }
> public void sessionCreated(IoSession session) throws Exception {
> ReadThrottleFilterBuilder throttleFilter = new
> ReadThrottleFilterBuilder();
> throttleFilter.attach(session.getFilterChain());
> }
> };
> SocketAcceptor acceptor = new SocketAcceptor();
> acceptor.bind(new InetSocketAddress(PORT), handler);
>
> Socket socket = new Socket("localhost", PORT);
> Writer writer = new OutputStreamWriter(socket.getOutputStream());
>
> while (true) {
> writer.write("test");
> writer.flush();
> }
> }
> }
>
> I have tried the test with version 1.0.1 and the current trunk (with the
> current trunk it takes longer until the memory
> error occures).
> Should I attach the test to
> https://issues.apache.org/jira/browse/DIRMINA-338 and reopen the issue?
It takes very long for me to reproduce the problem. I guess you can get rid
of this problem trying these options:
1) Increase max total direct buffer size using -XX:MaxDirectMemorySizeoption (
e.g. -XX:MaxDirectMemorySize=128M)
2) Change the allocator to SimpleByteBufferAllocator (i.e.
ByteBuffer.setAllocator(new SimpleByteBufferAllocator());)
3) Allocate heap buffers instead of direct buffers (i.e.
ByteBuffer.setUseDirectBuffers(false);)
Please try each step not reverting back the previous step. I believe
OutOfMemoryError will be gone once you reach to the step 3, but please let
me know the result.
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
Re: OutOfMemory when using ReadThrottleFilter
Posted by Swen Moczarski <ma...@swenmoc.de>.
Hi Trustin,
thanks a lot for your response.
Trustin Lee wrote:
> Hi Swen,
>
> On 1/4/07, Swen Moczarski <ma...@swenmoc.de> wrote:
>>
>> Hi, I have done some performance tests. A client is sending a lot of
>> small
>> messages over a connection to a server. In
>> spite of the read-throttle-filter (
>> org.apache.mina.filter.ReadThrottleFilterBuilder) the server will be
>> overloaded and I
>> get out-of-memory exceptions.
>>
>> Before the message will be forwarded to the ExecutionFilter, the
>> ReadThrottleFilter makes use of ByteBuffer.remaining()
>> for increasing the calculated size of the connection buffer. But after
>> passing the ExecutionFilter the method
>> ByteBuffer.capacity() is used to decrease the size. Is that behaviour
>> intended?
>>
>> When I'm patching the ReadThrottleFilterBuilder to use
>> ByteBuffer.capacity()
>> for both cases the performance test works
>> absolutely fine, there are no longer out-of-memory exceptions. BTW, in
>> the
>> SVN-history I have seen that the first
>> version uses ByteBuffer.capacity() for both cases.
>
>
> It seems like there was a mistake. Could you try to change both capacity()
> calls to remaining()? I think it's a correct fix than using capacity().
>
When I'm using the remaining() calls, I still get an out-of-memory error. But when I'm using capacity() it looks ok.
Maybe, this becomes only a problem when a lot of small messages are stored in bigger ByteBuffers. But I think it would
be safer to prevent overloading when the ReadThrottleFilter tracks the memory allocated by the ByteBuffers (capacity())
instead of the received bytes. WDYT?
Here is my simple stess-test:
public class Test {
private final static int PORT = 8056;
public static void main(String[] args) throws Exception {
IoHandler handler = new IoHandlerAdapter() {
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
cause.printStackTrace();
}
public void sessionCreated(IoSession session) throws Exception {
ReadThrottleFilterBuilder throttleFilter = new ReadThrottleFilterBuilder();
throttleFilter.attach(session.getFilterChain());
}
};
SocketAcceptor acceptor = new SocketAcceptor();
acceptor.bind(new InetSocketAddress(PORT), handler);
Socket socket = new Socket("localhost", PORT);
Writer writer = new OutputStreamWriter(socket.getOutputStream());
while (true) {
writer.write("test");
writer.flush();
}
}
}
I have tried the test with version 1.0.1 and the current trunk (with the current trunk it takes longer until the memory
error occures).
Should I attach the test to https://issues.apache.org/jira/browse/DIRMINA-338 and reopen the issue?
Regards,
Swen