【问题标题】:Java - "no buffer space available" socket error cause?Java - “没有可用的缓冲区空间”套接字错误原因?
【发布时间】:2011-05-25 02:37:33
【问题描述】:

我正在用 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 方法来关闭它。我还有一个 finalize 方法来关闭 ServerSocket 所以我不知道问题是什么。

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

我真的无法解决这个问题,而且我多年来一直在尝试解决这个问题。有谁知道问题出在哪里?

提前致谢!

更新:

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

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

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

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

有人知道为什么会这样吗?

非常感谢。

【问题讨论】:

  • 问题是否取决于打开/关闭的套接字数量?修改后的代码是 only 打开套接字的代码吗?是否可重复运行?

标签: java sockets tcp buffer serversocket


【解决方案1】:

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

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

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

从上面的链接:

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

编码愉快。

编辑:请参阅此相关问题:Why would you ever implement finalize()?。我喜欢 Steve Jessop 的第二次回复。

【讨论】:

  • 我已经更新了我的代码,以便不使用终结器来关闭套接字,但我仍然收到错误(请参阅上面的更新)。知道为什么吗?谢谢
【解决方案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
        }
    }

【讨论】:

  • 我已经尝试过了(请参阅原始问题中的更新),但由于某种原因仍然出现错误(如上所述)。知道为什么吗?谢谢
  • @tree-hacker - 你怎么知道是代码泄露了资源?您是否使用内存分析器/转储分析器证明了这一点?
  • 不,但是当我在关闭套接字的行之后添加代码行“System.gc()”时,我得到一个不同的运行时错误,但 gc 永远不应该改变程序的行为,所以我认为错误与资源收集不正确或类似情况有关?
  • @tree-hacker - 正如我们一直试图告诉你的那样 - 不要依赖 GC 来回收套接字和流等资源。更重要的是断言 "... gc 永远不会改变程序的行为" 是 false 如果任何回收的对象具有终结器(套接字等) .
  • @tree-hacker - 我的建议是停止填充并使用内存分析器/转储分析器来查找资源泄漏。
猜你喜欢
  • 2018-03-11
  • 2018-05-10
  • 2012-04-26
  • 1970-01-01
  • 2018-08-29
  • 2016-08-08
  • 2021-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多