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语言峰会

今年的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目录下的包/类,因此,系统级的类是相对安全的。
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默认采用了 ” 双亲委派的加载链 ” 结构.
如下图:

Class Diagram:

类图中, 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
