我正在尝试理解在OracleJVM中运行的Java应用程序服务器的strace
。
我经常看到这样的行:
[pid 10465] 23:04:59.658453 dup2(215, 274) = 274
[pid 10465] 23:04:59.658616 close(274) = 0
在这种情况下,215
是一个UNIX套接字:
java 10387 XXX 215u unix 0xffff880037962cc0 0t0 153294021 socket
FD 274
是一个开放TCP套接字。
这些"呼叫对"使用同一个A
套接字在数分钟内重复多次。
我对dup2(A, B)
的理解是,它创建了一个指向/引用同一文件/套接字A
的文件描述符B
,如果它仍然打开,则首先关闭B
。
Opengroup称
dup2((函数将使文件描述符filtdes2引用与文件描述符filtes相同的打开文件描述,并共享任何锁,并返回filtdes2。如果filtes2已经是一个有效的打开文件描述符,则应首先关闭它,除非filtes等于filtes2,在这种情况下,dup2((应返回filtdes2而不关闭它。
到目前为止,我唯一的猜测是,这是JVM的一种奇怪的、未优化的行为。不是吗?这有什么意义。
如有必要,我将添加更多上下文调用。
这个序列提供了一种线程安全的方法来关闭套接字。
dup2
允许在不释放文件描述符的情况下关闭套接字。由于未传输的数据和较长的延迟间隔,这可能是一个漫长的操作。dup2(A, B)
是的原子等价物
close(B);
fcntl(A, F_DUPFD, B);
即CCD_ 11在任何时候都保持有效描述符。在所有已获取该描述符的线程完成未完成的I/O操作之前,保持文件描述符的有效性至关重要。
被复制的fd
(在您的情况下为215(是shutdown
状态下的一个特殊标记套接字。它创建一次,唯一的目的是通过dup2
关闭其他套接字。一旦dup2
完成,从原始fd
(274(的任何读取都将返回EOF,并且对其的任何写入都将得到错误。
Java为每个文件描述符维护一个使用计数器。线程在获取文件描述符时递增该计数器,在完成I/O操作时递减该计数器。一旦use计数器降到0,Java就会调用close
来释放文件描述符,并使其可用于操作系统。
Java NIO实现使用相同的技术来关闭文件
尽管除了JDK源代码之外,我还没有见过这种模式。