【发布时间】:2016-10-01 06:34:51
【问题描述】:
我正在尝试理解 SO_TIMEOUT、线程资源和垃圾回收的概念。
我在我的项目中看到了一个编码错误,其中一组套接字在没有关闭的情况下被错误地取消引用。
使用 JAVA 1.6,它们会在几分钟内关闭,但使用 JAVA 1.8,它们需要数小时才能关闭。 [仅在linux平台测试]
所以我想更深入地研究这个问题。
我创建了这个程序,在其中创建了 10 个套接字,但正如您所见,其中 9 个被取消引用,然后线程进入长时间休眠:
import java.net.Socket;
/**
* Created by 212477559 on 5/30/16.
*/
public class TestClientSocket {
public static void main(String args[])
{
try
{
Socket socket;
for(int j=0;j<10;j++)
{
socket =new Socket("localhost",9090);
socket.setKeepAlive(false);
}
Thread.sleep(900000);
}
catch(Exception e)
{
System.out.println("throws");
e.printStackTrace();
}
}
}
现在当我运行时
netstat -np TCP |找到“9090”
我仍然可以看到半小时左右后所有套接字仍处于已建立状态。所以我有以下问题:
1) 为什么这 9 个套接字没有被垃圾回收?
2) 那个线程还持有资源吗?
3) 是下面提到的关闭套接字的唯一方法:
1. close the sockets?
2. Thread which created those sockets must exit?
3. SO_TIMEOUT should expire?
【问题讨论】:
-
关闭套接字是关闭套接字的唯一正确方法。垃圾收集不是资源清理机制,超时也不是。
-
您可能很想为此编写一个
finalize()方法,但不要这样做。当堆中的可用空间不足时,垃圾收集器运行。由于任何其他资源不足,它无法运行。 -
@zapl & james 我知道关闭套接字是正确的做法。我只是想了解我的项目问题,即它在不同的 Java 版本方面出了什么问题。所以想了解socket、线程和垃圾回收的关系
-
你的问题只是你没有关闭你的套接字。它与线程无关,线程休眠时引用的测试代码中唯一的套接字是自
socket仍然指向它之后创建的最后一个套接字。其余的可以免费作为 GC,但您的测试程序会产生 0 垃圾,因此 GC 不需要运行。超时不会导致清理。当您调用 read 或 write 方法时,它们会给您例外。 -
垃圾收集器没有理由在你的程序中运行。你创建了 10 个对象,然后永远沉睡。之后不会创建垃圾。在那之后也没有什么需要记忆的。对内存的需求是垃圾收集的驱动力。
标签: java multithreading sockets networking garbage-collection