0

我正在用 Java 编写一个网络程序。我使用 ServerSocket 和 Socket 对象通过 TCP 发送和接收消息。如果我的程序运行时间很短,我的程序运行良好,但是如果我运行它更长的时间,我会收到以下错误:

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)

我认为这可能是因为我没有关闭所有套接字,但我更改了代码:我有一个类,当我想要一个新套接字时创建一个类,并添加了一个 finalize 方法来关闭它。我还有一个关闭 ServerSocket 的 finalize 方法,所以我不知道问题是什么。

同样在我收到错误后,如果我立即再次运行该程序,它会比以前更快地遇到问题。然后,如果我等待一段时间并运行它,它会回到原来的时间。

我真的无法解决这个问题,我一直在努力解决这个问题。有谁知道问题是什么?

提前致谢!

更新:

所以我已经弄清楚错误来自哪里,这真的很奇怪。我有以下导致问题的代码:

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();
        }
    }

如您所见,代码应该打开一个套接字并写入它。但是,即使所有功能代码都像上面那样被注释掉,所以套接字只是打开然后立即关闭,我仍然得到“没有缓冲区空间”错误。

我真的不知道为什么会这样。该程序是多线程的,每个线程使用上述方法定期创建对象并调用它。当创建和关闭套接字的行被删除时,我不再收到错误,但是当它们在那里时,即使套接字打开然后立即关闭,我也会收到错误。

有谁知道为什么会这样?

非常感谢。

4

2 回答 2

5

当我想要一个新的套接字并添加了一个finalize方法来关闭它时,我创建了一个类。我还有一个关闭 ServerSocket 的finalize方法,所以我不知道问题是什么。

呸呸呸。停止。查看。终结器在运行时是不确定的(除非在对象不再可访问之后的某个时间,尽管即使 Java 应用程序终止也可能不是!) - 请参阅销毁和终结。确保您使用的是显式合约,例如Closable并通过调用它(不要等待 GC 出现!)。

这个问题最能说明“泄漏”外部资源——因为 GC 主要关心内存和内存压力,如果压力很小和/或 GC 不积极,很容易首先用完外部资源,因为终结器尚未运行(还)。一般来说,终结器是一个安全网(并不总是有效),但不能替代其他形式的外部资源管理。

从上面的链接:

Java 不保证何时会发生垃圾收集或收集对象的顺序。因此,Java 无法保证何时(甚至是否)调用终结器、调用终结器的顺序或执行终结器的线程。

快乐编码。

编辑:看到这个相关的问题:你为什么要实现 finalize()?. 我喜欢史蒂夫杰索普的第二个回应。

于 2010-12-14T06:53:00.693 回答
2

不要finalize用来关闭资源。它不会可靠地工作。

(资源对象有可能不会很快完成,并且您将耗尽资源。您无法控制终结器何时运行,并且它们可能永远不会运行。)

你应该做的是这样的:

    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
        }
    }
于 2010-12-14T07:00:09.850 回答