[讨论] 一些底层问题,比较零散

gooooooooa 2012-02-12
最近在回顾 Java IO 笔记本是mac,平台是openjdk6.

public FileOutputStream(File file, boolean append) throws FileNotFoundException

里面有这么一句:
this.fd = new FileDescriptor();


再看 FileDescriptor()
public FileDescriptor() { 
        fd = -1; 
        useCount = new AtomicInteger(); 
}

生成一个无效的 FileDescriptor

问题来了:这里生成一个无效的 FileDescriptor 意义在哪里?

还有想请教,当在深入底层看一些java的机制时,必定会深入到native的代码。
此时,环境是如何的,开一个eclipse-->jdk源码 
再开一个 vs或者vim/emacs-->native c ?
一般研究这些底层代码时,较常用的一些工具是什么。

源码定位问题,比如我想看 java 遇到 synchronized时,他底层是怎么去做的,是编译时就翻译成另一个东西?
像 Cloneable 和 Serializable 这种标记接口,java又是如何去判断处理的。
要看这些机制,源码在哪里,如何快速定位
RednaxelaFX 2012-02-13
1、我手上没Mac版JDK的代码。它跟BSD版的代码更接近,而跟Linux版的的区别大一些。
Anyway,我从Linux版来告诉你这里发生什么事了。

FileOutputStream.java里有个open()方法的声明。它的定义在native代码里。
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_openAppend(JNIEnv *env, jobject this, jstring path) {
    fileOpen(env, this, path, fos_fd, O_WRONLY | O_CREAT | O_APPEND);
}

void
fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
{
    WITH_PLATFORM_STRING(env, path, ps) {
        FD fd;

#ifdef __linux__
        /* Remove trailing slashes, since the kernel won't */
        char *p = (char *)ps + strlen(ps) - 1;
        while ((p > ps) && (*p == '/'))
            *p-- = '\0';
#endif
        fd = JVM_Open(ps, flags, 0666);
        if (fd >= 0) {
            SET_FD(this, fd, fid);
        } else {
            throwFileNotFoundException(env, path);
        }
    } END_PLATFORM_STRING(env, ps);
}

/*
 * Macros to set/get fd from the java.io.FileDescriptor.  These
 * macros rely on having an appropriately defined 'this' object
 * within the scope in which they're used.
 * If GetObjectField returns null, SET_FD will stop and GET_FD
 * will simply return -1 to avoid crashing VM.
 */

#define SET_FD(this, fd, fid) \
    if ((*env)->GetObjectField(env, (this), (fid)) != NULL) \
        (*env)->SetIntField(env, (*env)->GetObjectField(env, (this), (fid)),IO_fd_fdID, (fd))

如果上面这几段代码你能看懂,那么你应该可以发现这里的native code在“干坏事”,在open()过程中它会强行设置那个FileDescriptor实例里的字段。就像通过反射去设置了一个private字段一样。所以那个FileDescriptor实例不是无用的,里面设置到-1是为了避免跟有效的fd冲突,以便判断文件到底是不是正常打开了。

=============================

我很土,看OpenJDK代码的时候通常就是用SciTe或者vim。已经越来越少用IDE了。我基本上只在做纯Java的工程的时候才开Eclipse。

SciTe的文件中搜索挺好用的,基本上就像是方便的grep前端。

==============================

引用
要看这些机制,源码在哪里,如何快速定位

嗯这个问题很大…我不知道该从哪里开始。
例如synchronized,首先我会通过规范知道Java的synchronized关键字在JVM规范里规定要用配对的monitorenter/monitorexit来表示。然后我会去找找看各种JVM实现里这俩字节码是如何实现的。先在源码里文本搜索,然后慢慢缩小范围找到实际的实现;如果能配合调试那是最好。
haoweishow 2012-02-13
引用
我很土,看OpenJDK代码的时候通常就是用SciTe或者vim。已经越来越少用IDE了。我基本上只在做纯Java的工程的时候才开Eclipse。

SciTe的文件中搜索挺好用的,基本上就像是方便的grep前端。

请问R大,你们开发也都是用vim,SciTe吗?我在ubuntu(宿主win7,在ubuntu虚拟系统中搭建的开发环境)上安装netbeans,引入openjdk的源码,编译都是OK的。唯一的缺陷就是贼慢。
另外还有个慢就是,我每修改一次hotspot的代码,对项目进行build,都要花费20+分钟。撇开我的硬件配置,请问R大,如何提高这个效率呀?
RednaxelaFX 2012-02-13
我开发就是用vim。而且我没特别配置过vimrc,很土。这方面别学我。

=========================

撇开你的硬件配置我也不知道怎样能更快

我用来编译HotSpot VM的机器是16核的Xeon,编译的时候带上HOTSPOT_BUILD_JOBS=16,完全干净的build一次HotSpot VM大概1分钟,只改了少量cpp文件的时候增量编译瞬间就好了。所以编译不太痛苦…

我在笔记本上编译HotSpot VM也不是特别痛苦。上一代i5,8GB内存,开HOTSPOT_BUILD_JOBS=4干净build一次HotSpot VM大概是不到4分钟。

不知道你说的build一次要20分钟是整个OpenJDK都build了还是只build了HotSpot。如果是前者的话那真是神速…不过看样子应该是后者吧。你还是找台实体机弄点稍微好些的配置来跑吧。在虚拟机里build慢是正常的。
haoweishow 2012-02-13
我修改了hotspot的代码,重新执行make的时候,发现时间消耗在JDK上面了。
修改make脚本:
make debug_build BUILD_JAXWS=false BUILD_JAXP=false BUILD_JDK=false

速度快很多,1~4分钟不等,以前BUILD_JDK就花了18分钟左右。

以后还是用脚本老老实实make,再也不用netbeans来make了。

PS:讨论这个有点喧宾夺主,请楼主请不要介意!
谢谢R大的回复。
RednaxelaFX 2012-02-13
其实你可以直接在hotspot目录里make的咯,那样自然就不会去build出JDK的其它部分,就很快,也不用指定BUILD_XXX=false
Global site tag (gtag.js) - Google Analytics