Archives

  • JVM优化之压缩普通对象指针(CompressedOops)

    通常64位JVM消耗的内存会比32位的大1.5倍,这是因为对象指针在64位架构下,长度会翻倍(更宽的寻址)。
    对于那些将要从32位平台移植到64位的应用来说,平白无辜多了1/2的内存占用,这是开发者不愿意看到的。
    幸运的是,从JDK 1.6 update14开始,64 bit JVM正式支持了 -XX:+UseCompressedOops 这个可以压缩指针,起到节约内存占用的新参数。

    什么是 OOP ?

    OOP = “ordinary object pointer” 普通对象指针。

    启用CompressOops后,会压缩的对象:
    ? 每个Class的属性指针(静态成员变量)
    ? 每个对象的属性指针
    ? 普通对象数组的每个元素指针

    当然,压缩也不是万能的,针对一些特殊类型的指针,JVM是不会优化的。
    比如指向PermGen的Class对象指针,本地变量,堆栈元素,入参,返回值,NULL指针不会被压缩。
    Read more…

    2009/09/01 | Posted in JVM, Performance Tuning
  • IcedTea 7 1.11版发布了

    什么是IcedTea?
    当SUN将全部Java源代码——现在称为OpenJDK——在2007年5月9日发布时,它还面临一些问题。 最主要的问题是有些代码的“缺失”。多年来,Sun得到的Java类库来自于多种渠道,因此,这些类库对应的许可种类也不一样,其中有些代码不允许开源。 为了能够使用这些受限代码,Sun提供了一些“二进制插件”,这些二进制插件被拷到构建(build)后的结果中。 这种做法的问题正如Fedora规则所讲的“别使用那些不开源的东西”那样,因为我们很难对看不见的代码保持信心。
    GNU Classpath团队和一些RedHat开发者一起创造了IcedTea 项目,目的就是要用开源实现去替换OpenJDK中那些非开源部分。

    提供openjdk 7 milestone 4编译的IcedTea 7 1.11版发布了.
    主要的改进是
    1, 支持 OpenJDK7 b66 (Milestone 4).
    2, netx组件的一些bug fix.
    3, zero装配器被正式支持.
    4, 一些参数被取消.如下
    * –with-openjdk
    * –with-icedtea
    * –with-openjdk-home
    * –with-icedtea-home
    * –with-gcj-jdk
    5, 使用systemtap 0.99+ 提供java方法跟踪.
    6, fix一些安全问题.

    2009/08/07 | Posted in JVM
  • 2009 JVM语言峰会

    2009 jvm语言峰会logo
    今年的JVM语言峰会将于9月16日-18日在加州圣塔克莱拉大学举行.
    上一届峰会共有75名语言和VM开发者参加, 但最后只有1/3的人出席.

    峰会跟往年一样, 有历时3天的主题演讲和交流沙龙, 也有JVM未来畅想之类的活动.
    点击 这里 可以看大会议程.

    从议程上看, 本届的亮点可能会在动态语言的支持上. 其中我发现一个名字很有趣的项目, 叫达芬奇, 它的目标是让JVM可以运行更多的其他语言, 主要是动态语言.
    项目链接 the Da Vinci Machine Project

    在主题演讲中, 我个人比较感兴趣的是, Clojure, Scala, JVM Performance 这三个主题.(最近Scala在国内比较热)
    今天杭州的天气不错, 希望这届峰会可以办得风风火火.

    2009/08/07 | Posted in JVM
  • java 安全沙箱模型详解

    起到第一道安全保障作用的”双亲委派类加载模型”

    双亲委派方式的类加载,指的是优先从顶层启动类加载器开始,自顶向下的方式加载类的模型(参见第一条类装载器体系结构)。

    这种模型的好处是,底层的类装载器装载的类无法与顶层类装载器装载的类相互调用。
    哪怕是同包下的类,只要他们不属于同一类装载器,都是相互隔绝的。这对一些有安全隐患的类起到了安全隔离的作用。使它不能冒充系统类来破坏程序正常运作。

    此外,不同的类装载器,也有自己的类装载范围。比如启动类装载器,它只会装在jdk/lib目录下的包/类,因此,系统级的类是相对安全的。

    java类加载模型
    Read more…

    2008/08/07 | Posted in JVM
  • java类加载器体系结构(含hotswap原理)

    jvm classLoader architecture :

    a, Bootstrap ClassLoader/启动类加载器
    主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作.

    b, Extension ClassLoader/扩展类加载器
    主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作

    c, System ClassLoader/系统类加载器
    主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作.

    b, User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
    在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性.

    类加载器的特性:

    1, 每个ClassLoader都维护了一份自己的名称空间, 同一个名称空间里不能出现两个同名的类。
    2, 为了实现java安全沙箱模型顶层的类加载器安全机制, java默认采用了 ” 双亲委派的加载链 ” 结构.
    如下图:
    java class loader

    Class Diagram:
    classloader 类图

    类图中, BootstrapClassLoader是一个单独的java类, 其实在这里, 不应该叫他是一个java类。
    因为, 它已经完全不用java实现了。
    Read more…

    2007/10/29 | Posted in JVM
  • bootstrap类加载原理

    让我们一起跟随ClassLoader里的本地方法 findBootstrapClass(), 进入jvm执行启动类加载器加载类的内部实现。

    private Class findBootstrapClass0(String name)
        throws ClassNotFoundException
        {
        check();
        if (!checkName(name))
            throw new ClassNotFoundException(name);
        return findBootstrapClass(name);
        }
     
        private native Class findBootstrapClass(String name)
        throws ClassNotFoundException;
    // 摘自 j2sesrcshareclassesjavalangClassLoader.c
    // 表示该函数将被 java class 以jni方式调用
    JNIEXPORT jclass JNICALL
    Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader,
    jstring classname)
    {
        char *clname;
        jclass cls = 0;
        char buf[128];
     
        if (classname == NULL) {
            // 类名不能为空
            JNU_ThrowClassNotFoundException(env, 0);
            return 0;
        }
     
        // 将java的string转成unicode字符, 如果unicode字符长度不超过128
        // 则不分配内存,直接拿buf缓存来使用
        // 否则就malloc一块内存存放, 如果malloc失败, 则返回NULL
        clname = getUTF(env, classname, buf, sizeof(buf));
        if (clname == NULL) {
           // 类名为空, 说明 JVM 内存分配失败, 抛出邪恶的OOM.
           JNU_ThrowOutOfMemoryError(env, NULL);
           return NULL;
        }
     
        // 将 '.' 转换成 '/'
        VerifyFixClassname(clname);
     
        if (!VerifyClassname(clname, JNI_TRUE)) {
          // 如果指定的类名不合法, 抛出异常
          JNU_ThrowClassNotFoundException(env, clname);
          goto done;
        }
     
        // 让jvm使用启动类加载器加载类, 第四位标志0表示使用启动类加载器,
        // throwError为JNI_FALSE时抛出 ClassNotFoundException,而JNI_TRUE抛出NoClassDefFoundError
        cls = JVM_FindClassFromClassLoader(env, clname, JNI_FALSE, 0, JNI_FALSE);
     
    done:
        if (clname != buf) {
           // 类名的格式有问题,且没有走buf缓存,则释放掉创建的内存, 防止内存泄漏
           free(clname);
        }
     
        return cls;
    }
    // 摘自 hotspotsrcsharevmprimsjvm.h
    /*
    * jvm.h头文件, 类似java接口的定义。
    × 根据给定的classLoader来加载指定类
    ×
    × *env JNI运行环境
    × *name 类名(路径)
    × init 是否需要初始化类的内部数据结构
    × loader 类加载器标识
    × throwError 抛出的异常类型
    */
    JNIEXPORT jclass JNICALL
    JVM_FindClassFromClassLoader(JNIEnv *env, const char *name, jboolean init,
    jobject loader, jboolean throwError);
    // 摘自 hotspotsrcsharevmprimsjvm.cpp
    JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name,
         jboolean init, jobject loader,jboolean throwError))
     
    JVMWrapper3("JVM_FindClassFromClassLoader %s throw %s", name,
    throwError ? "error" : "exception");
     
    // 确保字符串不为NULL且长度不大于 (1 << 16) -1 , 否则抛出异常
    if (name == NULL || (int)strlen(name) > symbolOopDesc::max_length()) {
        if (throwError) {
           THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), name);
        } else {
           THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), name);
        }
    }
     
    // 将类名放入一个hashmap, 标记符号用的, 并构造为 symbolHandle
    // (注意: Handle是一种间接的, 由线程变量分配空间的类,作用是防止GC回收)
    // CHECK_0是一个宏, 作用是判断是否有没有处理掉的异常, 如果有, 返回0
    symbolHandle h_name = oopFactory::new_symbol_handle(name, CHECK_0);
     
    // 将classLoader标识转换成JVM内部表示的数据结构, 并构造为 Handle
    Handle h_loader(THREAD, JNIHandles::resolve(loader));
     
    jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
    Handle(), throwError, thread);
     
    if (TraceClassResolution && result != NULL) {
     trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
    }
     
    return result;
    JVM_END
    // 摘自 hotspotsrcsharevmprimsjvm.cpp
    jclass find_class_from_class_loader(JNIEnv* env, symbolHandle name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS) {
     
    // 生成类的内部数据结构, 核心步骤,非常复杂, 后期补充一下这里, 但是对核心逻辑没影响
    klassOop klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError, CHECK_0);
     
    // 将类的数据结构, 构造为 KlassHandle
    KlassHandle klass_handle(THREAD, klass);
     
    if (init && klass_handle->oop_is_instance()) {
    // 初始化类内部的数据结构
    klass_handle->initialize(CHECK_0);
    }
     
    // 分配内存, 生成class对象
    return (jclass) JNIHandles::make_local(env, klass_handle->java_mirror());
    }
    2007/10/07 | Posted in JVM
Archive for the ‘JVM’ Category