类加载流程-01

从本文开始讲述类加载过程,在这里先解释一下类加载的时机是什么?

此时可以分为2种情况:

  1. 主动引用
  2. 被动引用

类的主动引用指的是:

  1. new一个类的对象
  2. 调用类的静态成员(除了final常量)和静态方法
  3. 使用java.lang.reflect包的方法对类进行反射调用
  4. 当虚拟机启动,java Demo01,则一定会初始化Demo01类,说白了就是先启动main方法所在的类
  5. 当初始化一个类,如果其父类没有被初始化,则先初始化它父类

类的被动使用指的是:

  1. 当访问一个静态域时,只有真正声名这个域的类才会被初始化
    通过子类引用父类的静态变量,不会导致子类初始化
  2. 通过数组定义类的引用,不会触发此类初始化
  3. 引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了

但是,jvm在启动过程中会预先加载一些类,如 object之类的. 该链条如下:

-- main (java.c)
  -- JavaMain (java.c)
    -- InitializeJVM (java.c)  
      -- create_vm (thread.cpp)
       -- init_globals (init.cpp)
         -- universe2_init (universe.cpp)
           -- genesis (universe.cpp)
             -- initialize (systemDictionary.cpp)
               -- initialize_preloaded_classes (systemDictionary.cpp)
                 -- initialize_wk_klasses_through (systemDictionary.cpp)
                    -- initialize_wk_klasses_until (systemDictionary.cpp)
                      -- initialize_wk_klass ( systemDictionary.cpp)
                         -- resolve_or_fail (systemDictionary.cpp)
                           --resolve_instance_class_or_null ( systemDictionary.cpp)
                             -- load_instance_class ( systemDictionary.cpp)
                                -- load_classfile ( classLoader.cpp)
                                  -- parseClassFile ( ClassFileParser.cpp )  此处就开始加载了...

那么本文从何处讲起呢? 先从Universe::genesis 该方法讲起.

解析

Universe::genesis 方法如下:

void Universe::genesis(TRAPS) {
  ResourceMark rm;
  { FlagSetting fs(_bootstrapping, true);

    { MutexLocker mc(Compile_lock);

      // determine base vtable size; without that we cannot create the array klasses 决定
      compute_base_vtable_size();

      if (!UseSharedSpaces) {
        _klassKlassObj          = klassKlass::create_klass(CHECK);
        ..... 改处创建一系列的klass
      } else {
        FileMapInfo *mapinfo = FileMapInfo::current_info();
        char* buffer = mapinfo->region_base(CompactingPermGenGen::md);
        void** vtbl_list = (void**)buffer;
        init_self_patching_vtbl_list(vtbl_list,
                                     CompactingPermGenGen::vtbl_list_size);
      }
    }

    vmSymbols::initialize(CHECK);

    SystemDictionary::initialize(CHECK);

    klassOop ok = SystemDictionary::Object_klass();

    _the_null_string            = StringTable::intern("null", CHECK);
    _the_min_jint_string       = StringTable::intern("-2147483648", CHECK);

    if (UseSharedSpaces) {
      // 此处不执行
      } else {
      // Set up shared interfaces array.  (Do this before supers are set up.)
      _the_array_interfaces_array->obj_at_put(0, SystemDictionary::Cloneable_klass());
      _the_array_interfaces_array->obj_at_put(1, SystemDictionary::Serializable_klass());

      // Set element klass for system obj array klass
      objArrayKlass::cast(_systemObjArrayKlassObj)->set_element_klass(ok);
      objArrayKlass::cast(_systemObjArrayKlassObj)->set_bottom_klass(ok);

      // Set super class for the classes created above
      Klass::cast(boolArrayKlassObj()     )->initialize_supers(ok, CHECK);
       // .... 省略其他代码
     }

    Klass::cast(boolArrayKlassObj()     )->append_to_sibling_list();
    Klass::cast(charArrayKlassObj()     )->append_to_sibling_list();
    Klass::cast(singleArrayKlassObj()   )->append_to_sibling_list();
    Klass::cast(doubleArrayKlassObj()   )->append_to_sibling_list();
    Klass::cast(byteArrayKlassObj()     )->append_to_sibling_list();
    Klass::cast(shortArrayKlassObj()    )->append_to_sibling_list();
    Klass::cast(intArrayKlassObj()      )->append_to_sibling_list();
    Klass::cast(longArrayKlassObj()     )->append_to_sibling_list();
    Klass::cast(constantPoolKlassObj()  )->append_to_sibling_list();
    Klass::cast(systemObjArrayKlassObj())->append_to_sibling_list();
  } // end of core bootstrapping

  
  _objectArrayKlassObj = instanceKlass::
    cast(SystemDictionary::Object_klass())->array_klass(1, CHECK);
  
  Klass::cast(_objectArrayKlassObj)->append_to_sibling_list();

  // Compute is_jdk version flags.
  // Only 1.3 or later has the java.lang.Shutdown class.
  // Only 1.4 or later has the java.lang.CharSequence interface.
  // Only 1.5 or later has the java.lang.management.MemoryUsage class.
  if (JDK_Version::is_partially_initialized()) {
    uint8_t jdk_version;
    klassOop k = SystemDictionary::resolve_or_null(
        vmSymbolHandles::java_lang_management_MemoryUsage(), THREAD);
    CLEAR_PENDING_EXCEPTION; // ignore exceptions
    if (k == NULL) {
      k = SystemDictionary::resolve_or_null(
          vmSymbolHandles::java_lang_CharSequence(), THREAD);
      CLEAR_PENDING_EXCEPTION; // ignore exceptions
      if (k == NULL) {
        k = SystemDictionary::resolve_or_null(
            vmSymbolHandles::java_lang_Shutdown(), THREAD);
        CLEAR_PENDING_EXCEPTION; // ignore exceptions
        if (k == NULL) {
          jdk_version = 2;
        } else {
          jdk_version = 3;
        }
      } else {
        jdk_version = 4;
      }
    } else {
      jdk_version = 5;
    }
    JDK_Version::fully_initialize(jdk_version);
  }

}

计算vtable最小大小

什么是vtable? 在上篇文章有所介绍,此处再次介绍一下:

虚方法是c++的一个概念,c++中实现多态,是通过virtual 关键字,其底层是通过虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。

但是,问题来了,在JVM中是不能使用virtual的,因此,将一个类中 非static,非final,非private的方法都看做是 虚方法. 并通过vtable的技术来实现.

回到正题,我们来看一看compute_base_vtable_size,方法的实现:

void Universe::compute_base_vtable_size() {
  _base_vtable_size = ClassLoader::compute_Object_vtable();
}

注意,这里的_base_vtable_size 是 universe的全局变量,声明如下:

int             Universe::_base_vtable_size = 0;

ok,接下来我们来看一下ClassLoader::compute_Object_vtable方法:

int ClassLoader::compute_Object_vtable() {
  // hardwired for JDK1.2 -- would need to duplicate class file parsing
  // code to determine actual value from file
  // Would be value '11' if finals were in vtable
  int JDK_1_2_Object_vtable_size = 5; 
  return JDK_1_2_Object_vtable_size * vtableEntry::size();
}

一句话来总结,其最终的返回值是 5 * vtableEntry::size().

那么5 是啥意思呢? 我们都知道, java中的顶层父类为object,按照vtable的定义,object中恰好定义了如下方法:


public native int hashCode();

public boolean equals(Object obj) {
	return (this == obj);
}

protected native Object clone() throws CloneNotSupportedException;

public String toString() {
   return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

protected void finalize() throws Throwable { }

vtableEntry::size()方法如下:

static int size() {
    return sizeof(vtableEntry) / sizeof(HeapWord);
}

由于vtableEntry定义了如下字段:

methodOop _method; // 该类型为  methodOopDesc*,在32位上为长度4

同理,HeapWord 定义如下:

class HeapWord {
  friend class VMStructs;
 private:
  char* i;
#ifndef PRODUCT
 public:
  char* value() { return i; }
#endif
};

因此,sizeof(HeapWord)等于4

那么vtableEntry::size()返回的结果就是 4/4 = 1 (words)

那么ClassLoader::compute_Object_vtable()返回的结果就是 : 5 * 1 = 5 (words).

后续流程,下文分解

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值