0

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.

tree-hacker
  • 5,351
  • 9
  • 38
  • 39
  • Does the problem depend upon the number of sockets opened/closed? And the revised code is the *only* code which opens a socket? Is it run repeatably? –  Dec 15 '10 at 17:56

2 Answers2

5

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.

Community
  • 1
  • 1
  • I've updated my code so as not to use finalizers to close the socket but I still get an error (see update above). Any idea why? thanks – tree-hacker Dec 14 '10 at 20:04
2

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
        }
    }
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I've tried this (see update in original question) but I still get an error for some reason (explained above). Any idea why? Thanks – tree-hacker Dec 14 '10 at 20:03
  • @tree-hacker - how do you know that it is that code that is leaking resources? Have you proven it using a memory profiler / dump analyser? – Stephen C Dec 14 '10 at 23:27
  • No but when I add the code line "System.gc()" after the line closing the socket I get a different run time error but gc should never change the behavior of a program so I think the error is something to do with resources not being collected properly or something similar? – tree-hacker Dec 15 '10 at 00:26
  • @tree-hacker - as we've been trying to tell you - DON'T rely on GC to reclaim resources like sockets and streams. What is more the assertion *"... gc should never change the behaviour of a program"* is **false** if any of the objects reclaimed have finalizers (which sockets, etc do). – Stephen C Dec 15 '10 at 03:40
  • @tree-hacker - my advice is to stop stuffing around and use a memory profiler / dump analyser to find the resource leak. – Stephen C Dec 15 '10 at 03:41