new to NIO: how to close socketchannels properly?
Hi all,
I've recently started using the NIO packages to handle my networking applications, so i'm very new to how it all works.
I've written a simple server application that streams a constant stream of data to connecting clients, and during stress testing i've noticed a (possible) memory leak in my server.
my stress test involves initially connecting a number (lets say 1000) clients to the server, and at random time intervals, disconnecting a random number of the clients, and connecting that same number of new clients (so there are always 1000 clients connected).
using jconsole to watch the memory usage of my server it constantly increases over time. and letting it run indefinitely results in an out of memory error.
on to my server code:
i initialise the server by:
private AbstractSelector selector;
selector = SelectorProvider.provider().openSelector();
serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
InetSocketAddress isa =new InetSocketAddress(getPort());
serverChannel.socket().bind(isa);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
then start a loop (done in a Tread.run() function) that goes something like this (i've removed try catches and other complexity):
while (notkilled){
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()){
ServerSocketChannel channel = (ServerSocketChannel)key.channel();
SocketChannel client = channel.accept();
client.configureBlocking(false);
SelectionKey readKey = client.register(selector, SelectionKey.OP_WRITE);
readKey.attach(new ClientCallback(client));
}
if (key.isWritable()){
writeToChannel((ClientCallback)key.attachment());
}
}
}
this is the part that i'm worried about. I'm not sure i'm properly detecting disconnects, and i'm not sure I'm getting rid of everything to do with that channel (i.e. the ClientCallback instance attached, the key, and anything else involved).
privatevoid writeToChannel(ClientCallback client){
try{
client.execute();
}catch (IOException e){
try{
System.out.println("closing connection to: " + client.getChannel().socket().getRemoteSocketAddress().toString());
client.getChannel().close();
}catch (IOException e1){
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
and here is a very cut back representation of the client callback:
publicclass ClientCallback{
private SocketChannel channel;
public ClientCallback(SocketChannel channel){
this.channel = channel;
}
publicvoid execute()throws IOException{
channel.write(data)// psuedo coded, data exists somewhere
}
public SocketChannel getChannel(){
return channel;
}
}
Can anyone see any obvious memory leak issues in this code? As i said, i'm worried that i'm not closing the channels correctly.
Thanks in advance for any help :)
-Tristan

