想问下ServerSocket构造方法中的backlog参数最终在JVM中是怎么样生效的
chainhou
2013-12-29
大家好,最近在分析一个Tomcat通道相关的问题是,为了验证其backlog属性,因此看到了ServerSocket的源码。
ServerSocket包含这样一个构造方法,可以接收backlog参数 public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException { setImpl(); if (port < 0 || port > 0xFFFF) throw new IllegalArgumentException( "Port value out of range: " + port); if (backlog < 1) backlog = 50; try { bind(new InetSocketAddress(bindAddr, port), backlog); } catch(SecurityException e) { close(); throw e; } catch(IOException e) { close(); throw e; } } 相应的bind方法: public void bind(SocketAddress endpoint, int backlog) throws IOException { ...//此处省略一些内容 if (backlog < 1) backlog = 50; try { SecurityManager security = System.getSecurityManager(); if (security != null) security.checkListen(epoint.getPort()); getImpl().bind(epoint.getAddress(), epoint.getPort()); getImpl().listen(backlog); bound = true; } catch(SecurityException e) { bound = false; throw e; } catch(IOException e) { bound = false; throw e; } } 从上面可以看出最终调用了其实现类的listen方法。 该方法在类PlainSocketImpl类内,并且其调用了一个native方法, protected synchronized void listen(int count) throws IOException { socketListen(count); } private native void socketListen(int count) throws IOException; 看到native方法的时候,一般比较头大,相应的代码不太会找。就在OpenJDK相应的路径内找到同名的PlainSocketImpl.c,最终找到了如下内容: /* * Class: java_net_PlainSocketImpl * Method: socketListen * Signature: (I)V */ JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_socketListen (JNIEnv *env, jobject this, jint count) { /* this FileDescriptor fd field */ jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); /* fdObj's int fd field */ int fd; if (IS_NULL(fdObj)) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); return; } else { fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); } /* * Workaround for bugid 4101691 in Solaris 2.6. See 4106600. * If listen backlog is Integer.MAX_VALUE then subtract 1. */ if (count == 0x7fffffff) count -= 1; if (JVM_Listen(fd, count) == JVM_IO_ERR) { NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Listen failed"); } } 一看其又调用了JVM_Listen,这个时候是真不知道怎么入手了,就开始按内容搜索,找到了下面的内容: openjdk\hotspot\src\share\vm\prims\jvm.cpp JVM_LEAF(jint, JVM_Listen(jint fd, jint count)) JVMWrapper2("JVM_Listen (0x%x)", fd); //%note jvm_r6 return os::listen(fd, count); JVM_END 一来对C的语法不熟悉,看到这个还是不知道如何找到最终的实现代码。 调试代码时如果跟到了JDK的native代码,这时候一般怎么下手找到关注的内容? PS:R大的博客里有一系列关于了解学习JVM的好内容,但我没找到关于如何跟踪代码相关的,谁知道相关内容请告诉一下。就是在调试代码时如果跟到了JDK的native代码,这时候一般怎么下手找到关注的内容呢? 谢谢。 |
|
simpleman7210
2013-12-30
我看到楼主跟踪到了os::listen(),其实这已经很近了。os应该是个C++类,jvm为了平台移植性,在os类里封装了与平台相关的实现。我没有打开OpenJDK工程观察这块代码,不过可以判断接下来就是调用平台所在的本地库函数了。比如在Windows上很可能是调用Windows的API函数listen()。listen()源代码一般是看不到的,因为在DLL(动态链接库)中。
|
|
RednaxelaFX
2013-12-31
楼主所说的“跟踪”有两种,静态与动态。
静态就像楼主那样只靠读源码来分析。这种方式在对源码越熟悉的情况下越有效。换句话说,如果对源码不熟就直接硬啃,效果通常不太好。 动态就是在程序运行过程中去发现信息。通常这会意味着要使用调试器。要跟C++代码的话可以用你熟悉的native debugger,例如Windows上Visual Studio自带的调试器、WinDBG或者如果没源码要做汇编级调试时用OllyDbg之类;Linux上GDB是王道。我还被迫用过一段时间dbx但始终不顺手 楼主多半需要native debugger的入门教程。如果是跟到Java的native方法而且你知道该native方法在C/C++那边的入口在哪里的话,只要用native debugger在那个入口处设断点然后慢慢跟就好了,不麻烦。 ====================================== HotSpot里,os是一个封装操作系统特定行为的静态类。 http://hg.openjdk.java.net/jdk7u/jdk7u/hotspot/file/tip/src/share/vm/runtime/os.hpp class os: AllStatic { // ... }; 它里面的函数的具体实现大多在hotspot/src/os里。 具体到os::listen(),具体实现取决于你在看什么版本和什么平台, 在JDK7的HotSpot里, Linux: http://hg.openjdk.java.net/jdk7u/jdk7u/hotspot/file/tip/src/os/linux/vm/os_linux.inline.hpp inline int os::listen(int fd, int count) { return ::listen(fd, count); } 也就是调用了listen() Windows: http://hg.openjdk.java.net/jdk7u/jdk7u/hotspot/file/tip/src/os/windows/vm/os_windows.cpp int os::listen(int fd, int count) { return ::listen(fd, count); } 也就是调用了listen() |
|
chainhou
2013-12-31
多谢R大和simpleman的回复。其实我主要是为了解决工作中遇到的一些问题。因为项目中用了一些开源产品,当测试发现问题时,就需要跟踪其源码,来确认问题。大学的时候其实也学过C++,也用过Visual Studio,但一直没学好,后来也没再学。
对于R大提到的native debugger,是需要在VS里把jvm代码加断点后以debug方式启动,之后java代码如果用到就会跳转过去是吗? 真心不懂。哎。 |
|
RednaxelaFX
2014-01-02
chainhou 写道 对于R大提到的native debugger,是需要在VS里把jvm代码加断点后以debug方式启动,之后java代码如果用到就会跳转过去是吗?
假定你用Visual Studio的debugger,那应该在JVM的代码上设断点,然后“附加”(attach)到你要调试的进程上,然后等断点触发。 问题是怎么才能让Visual Studio知道你要调试的jvm.dll里的代码跟你打开的JVM的源码是有关系的呢?最简单的办法就是那个jvm.dll是你自己build出来的,这样VS就肯定知道;不然的话请看各种入门教程 |
|
chainhou
2014-01-06
元旦期间请假了,一下没上网。谢谢R大耐心细致的回答。,祝新年快乐
|