Question

I'm writing a networking program in Java. I use ServerSocket and Socket objects to send and receive messages using TCP. My program runs fine if run for a short time however if I run it for a longer time, I get the following error:

java.net.SocketException: No buffer space available (maximum connections reached?): connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(Unknown Source)
at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)

I thought it might be because I do not close all sockets but I've changed my code: I have one class that I create when I want a new socket and have added a finalize method to close it. I also have a finalize method to close the ServerSocket so I don't know what the problem is.

Also after I get the error, if I run the program again straight away, it runs into the problem quicker than before. Then if I wait for a while and run it, it goes back to like the original time.

I really cannot work out the problem and I've been trying to figure it out for ages. Does anyone have any idea what the problem is?

Thanks in advance!

UPDATE:

So I've figured out where the error is coming from and it's really weird. I have the following code which is causing the problem:

try {
        sock = new Socket(InetAddress.getByName(ipaddr), port);
        sock.close();

        // os = sock.getOutputStream();
        // byte[] arr = s.getBytes();
        // os.write(arr);
        // os.close();

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            sock.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

As you can see, the code should open a socket and write to it. However even when all the functional code is commented out as above, so the socket is just opened then immediately closed, I still get the "no buffer space" error.

I really cannot work out why this is. The program is multi threaded and each thread creates objects periodically with the above method in and call it. When the lines to create and close the socket are removed, I no longer get the error but when they are there, even though the socket is opened then closed immediately, I get the error.

Does anyone have any clue why this is happening?

Many thanks.

Was it helpful?

Solution

I have one class that I create when I want a new socket and have added a finalize method to close it. I also have a finalize method to close the ServerSocket so I don't know what the problem is.

Bzzt. Stop. Check. Finalizers are non-deterministic when they run (except some time after the object is no longer reachable, although perhaps not even if the Java app terminates!) -- see Destroying and Finalizing. Make sure you are using a explicit contract such as Closable and invoking it through and through (don't wait for the GC to come about!).

This problem is most indicative of "leaking" external resources -- since the GC cares mostly about memory and memory pressure, if there is little pressure and/or the GC is not aggressive it is very easy to run out of the external resources first because the finalizers are not run (yet). In general, finalizer are a safety-net (that doesn't always work), but are not a replacement for other forms of external resource management.

From the link above:

Java makes no guarantees about when garbage collection will occur or in what order objects will be collected. Therefore, Java can make no guarantees about when (or even whether) a finalizer will be invoked, in what order finalizers will be invoked, or what thread will execute finalizers.

Happy coding.

Edit: See this related question: Why would you ever implement finalize()?. I like the 2nd response from Steve Jessop.

OTHER TIPS

Don't use finalize to close resources. It won't work reliably.

(There is a chance that the resource objects won't be finalized soon enough and you will run out of resources. You have no control of when the finalizers get run, and it is possible that they will never get run.)

What you should be doing is something like this:

    Resource resource = // allocate resource
    try {
        // Use the resource ...
    } 
    catch (SomeException ...) {
        // Deal with errors from using the resource
    } 
    finally {
        try {
            resource.close()}
        }
        catch (SomeException ...) {
            // Deal with errors from closing the resource
        }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top