类加载流程-002

本文让我们继续梳理类加载的流程,分析的代码为:

_klassKlassObj          = klassKlass::create_klass(CHECK);

这里先说明2个问题:

  1. 为啥要首先创建klassKlass?

    因为klassKlass 是klass链路的末端.不可能oop-klass 一直这么的指下去,必须有个终点.这个终点就是klassKlass.

  2. CHECK 是啥?

    CHECK 是宏,定义如下:

    #define CHECK                                    THREAD); if (HAS_PENDING_EXCEPTION) return       ; (0
    
    #define THREAD __the_thread__
    #define HAS_PENDING_EXCEPTION                    (((ThreadShadow*)THREAD)->has_pending_exception())
    #define TRAPS  Thread* THREAD
    

    那么因此宏展开后就是:

    _klassKlassObj          = klassKlass::create_klass(__the_thread__);
    
    if((((ThreadShadow*) __the_thread__)->has_pending_exception()))
      return ;
      
      (0);
      
    

    那么这里的 _the_thread_ 是哪来的呢?

    由于该方法是void Universe::genesis(TRAPS),宏展开后正好是:

    void Universe::genesis(Thread* __the_thread__)
    

    因此,该_the_thread_ 是由Universe::genesis方法的参数而来.

解析

klassKlass::create_klass方法实现如下:

klassOop klassKlass::create_klass(TRAPS) {
  KlassHandle h_this_klass;
  klassKlass o;
  // for bootstrapping, handles may not be available yet.
  klassOop k = base_create_klass_oop(h_this_klass, header_size(), o.vtbl_value(), CHECK_NULL);
  k->set_klass(k); // point to thyself 自指
  // Do not try to allocate mirror, java.lang.Class not loaded at this point.
  // See Universe::fixup_mirrors()
  return k;
}

这里有4行代码,很明显就做了4件事:

  1. 创建 KlassHandle
  2. 创建 klassKlass
  3. 创建 klassOop
  4. 自指

创建 KlassHandle

这里先贴一下KlassHandle的类图:

KlassHandle类图

由于创建 KlassHandle 所对应的代码为:

KlassHandle h_this_klass;

因此会执行如下代码:

 KlassHandle ()                                 : Handle()            {}

此时会执行Handle()的构造器:

Handle()                                       { _handle = NULL; }

此时的状态如图所示:

klasshandle-001

创建 klassKlass

这里先贴下klassKlass的类图:

klassklass类图
由于创建 klassKlass 所对应的代码为:

klassKlass o;

同时,由于没有定义构造器,因此这里也就没什么好说的了…

创建 klassOop

此处执行的代码为:

klassOop k = base_create_klass_oop(h_this_klass, header_size(), o.vtbl_value(), CHECK_NULL);

这里首先调用了header_size()方法,如下:

static int header_size()  { return oopDesc::header_size() + sizeof(klassKlass)/HeapWordSize; }

而 oopDesc::header_size() 实现如下:

static int header_size()          { return sizeof(oopDesc)/HeapWordSize; }

由于oopDesc 定义了如下字段:

volatile markOop  _mark;

union _metadata {
    wideKlassOop    _klass;
    narrowOop       _compressed_klass;
} _metadata;

那么在64位上,sizeof(oopDesc) 会返回如下结果:

  1. 如果未开启指针压缩,返回 16
  2. 如果开启指针压缩,返回 12

在 32位上,sizeof(oopDesc) 会返回如下结果: 8

因此,oopDesc::header_size() 会返回 2

同时,由于 sizeof(klassKlass)/HeapWordSize = 108/4 = 27 (32 位情况下)

因此,klassklass::header_size() 最终返回的是 29 .

另外, o.vtbl_value() 代码如下:

const Klass_vtbl& vtbl_value() const { return *this; }

回到Klass::base_create_klass_oop方法中,代码如下:

klassOop Klass::base_create_klass_oop(KlassHandle& klass, int size,
                                      const Klass_vtbl& vtbl, TRAPS) {
  size = align_object_size(size);
  // allocate and initialize vtable
  Klass*   kl = (Klass*) vtbl.allocate_permanent(klass, size, CHECK_NULL);
  klassOop k  = kl->as_klassOop();

  { // Preinitialize supertype information.
    // A later call to initialize_supers() may update these settings:
    kl->set_super(NULL);
    for (juint i = 0; i < Klass::primary_super_limit(); i++) {
      kl->_primary_supers[i] = NULL;
    }
    kl->set_secondary_supers(NULL);
    oop_store_without_check((oop*) &kl->_primary_supers[0], k);
    kl->set_super_check_offset(primary_supers_offset_in_bytes() + sizeof(oopDesc));
  }

  // 初始化Klass
  kl->set_java_mirror(NULL);
  kl->set_modifier_flags(0);
  kl->set_layout_helper(Klass::_lh_neutral_value);
  kl->set_name(NULL);
  AccessFlags af;
  af.set_flags(0);
  kl->set_access_flags(af);
  kl->set_subklass(NULL);
  kl->set_next_sibling(NULL);
  kl->set_alloc_count(0);
  kl->set_alloc_size(0);

  // JVM内部虽然将klass也封装成立oop,但是klass毕竟也是独立的一种类型,因此也需要记录线程锁等相关标识
  kl->set_prototype_header(markOopDesc::prototype());
  kl->set_biased_lock_revocation_count(0);
  kl->set_last_biased_lock_bulk_revocation_time(0);

  return k;
}

可以分为3部分:

  1. 内存对齐

  2. 将Klass分配在永久区

  3. 初始化klassOop的数据

内存对齐

此处内存对齐实现如下:

inline intptr_t align_object_size(intptr_t size) {
  return align_size_up(size, MinObjAlignment);
}

inline intptr_t align_size_up(intptr_t size, intptr_t alignment) {
  return align_size_up_(size, alignment);
}

#define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1))

MinObjAlignment  =  2

Klass分配在永久区

此处代码实现如下:

void* allocate_permanent(KlassHandle& klass_klass, int size, TRAPS) const { \
    void* result = new(klass_klass, size, THREAD) thisKlass();                \
    if (HAS_PENDING_EXCEPTION) return NULL;                                   \
    klassOop new_klass = ((Klass*) result)->as_klassOop();                    \
    OrderAccess::storestore();                                                \
    post_new_init_klass(klass_klass, new_klass, size);                        \
    return result;                                                            \
  }

注意,由于Klass_vtbl中重载了new操作符,如下:

void* operator new(size_t ignored, KlassHandle& klass, int size, TRAPS);

因此,此处最终执行的代码如下所示:

void* Klass_vtbl::operator new(size_t ignored, KlassHandle& klass,
                               int size, TRAPS) {
  // The vtable pointer is installed during the execution of
  // constructors in the call to permanent_obj_allocate().  Delay
  // the installation of the klass pointer into the new klass "k"
  // until after the vtable pointer has been installed (i.e., until
  // after the return of permanent_obj_allocate().
  klassOop k =
    (klassOop) CollectedHeap::permanent_obj_allocate_no_klass_install(klass,
      size, CHECK_NULL);
  return k->klass_part();
}

这里调用了CollectedHeap::permanent_obj_allocate_no_klass_install方法,代码如下:

oop CollectedHeap::permanent_obj_allocate_no_klass_install(KlassHandle klass,
                                                           int size,
                                                           TRAPS) {
  
  HeapWord* obj = common_permanent_mem_allocate_init(size, CHECK_NULL); // 为oop 申请内存
  post_allocation_setup_no_klass_install(klass, obj, size); // 初始化klassOop._mark标识
 
  return (oop)obj;
}

这里做了2件事:

  1. 为oop 申请内存
  2. 初始化klassOop._mark标识

先来看oop 申请内存的部分:

HeapWord* CollectedHeap::common_permanent_mem_allocate_init(size_t size, TRAPS) {
  HeapWord* obj = common_permanent_mem_allocate_noinit(size, CHECK_NULL); // 1. 为klassOop申请内存
  init_obj(obj, size); // 2. klassOop内存清零
  return obj;
}

2件事:

  1. 为klassOop申请内存
  2. klassOop内存清零

其中,申请内存最终执行的代码是:

 HeapWord* result = Universe::heap()->permanent_mem_allocate(size);
 
 if (result != NULL) {
   
    return result;
  }

这里,gc使用的是parallelScavenge,其最终分配内存代码如下:

 result = perm_gen()->allocate_permanent(size);

  if (result != NULL) {
    return result;
  }
  
  
  ------------ psPermGen.cpp --------
  
  HeapWord* PSPermGen::allocate_permanent(size_t size) {
  assert_locked_or_safepoint(Heap_lock);
  // 直接进行分配
  HeapWord* obj = allocate_noexpand(size, false);

  if (obj == NULL) {
    // 如果分配失败,则扩容后,在进行分配
    obj = expand_and_allocate(size, false);
  }

  return obj;
}

-------------psOldGen.hpp -----
HeapWord* allocate_noexpand(size_t word_size, bool is_tlab) {
    // We assume the heap lock is held here.
    assert(!is_tlab, "Does not support TLAB allocation");
    assert_locked_or_safepoint(Heap_lock);
    HeapWord* res = object_space()->allocate(word_size);
    if (res != NULL) {
      _start_array.allocate_block(res);
    }
    return res;
  }

这里最终会执行 MutableSpace::allocate 方法,如下:

HeapWord* MutableSpace::allocate(size_t size) {
  assert(Heap_lock->owned_by_self() ||
         (SafepointSynchronize::is_at_safepoint() &&
          Thread::current()->is_VM_thread()),
         "not locked");
  /*
   * 注意,这里先执行HeapWord* obj = top();再执行 HeapWord* new_top = obj + size;,而最终返回的是obj指针,该指针指向的是原来的堆的最顶端,
   * 这样,调用方通过指针可以还原从原顶端到当前堆顶之间的内存空间,将其强制转换为常量池对象.
   */
  HeapWord* obj = top();
  if (pointer_delta(end(), obj) >= size) {
    HeapWord* new_top = obj + size; // 将PermSpace内存区域的top指针往高地址移动了size大小的字节数,完成了当前被加载的类所对应的常量池的内存分配
    set_top(new_top);
    assert(is_object_aligned((intptr_t)obj) && is_object_aligned((intptr_t)new_top),
           "checking alignment");
    return obj;
  } else {
    return NULL;
  }
}

关键点都在注释中,这里就不在解释了…

接下来,我们来看一看内存清零部分:

void CollectedHeap::init_obj(HeapWord* obj, size_t size) {
  assert(obj != NULL, "cannot initialize NULL object");
  const size_t hs = oopDesc::header_size();
  assert(size >= hs, "unexpected object size");
  ((oop)obj)->set_klass_gap(0);
  Copy::fill_to_aligned_words(obj + hs, size - hs);
}
 static void fill_to_aligned_words(HeapWord* to, size_t count, juint value = 0) {
    assert_params_aligned(to);
    pd_fill_to_aligned_words(to, count, value);
  }

注意,这里的value 默认值是 0 .

--------copy_x86.hpp ----

static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) {
  pd_fill_to_words(tohw, count, value);
}


static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) {
#ifdef AMD64
  julong* to = (julong*) tohw;
  julong  v  = ((julong) value << 32) | value;
  while (count-- > 0) {
    *to++ = v;
  }
#else
  juint* to = (juint*)tohw;
  count *= HeapWordSize / BytesPerInt;
  while (count-- > 0) {
    *to++ = value;
  }
#endif // AMD64
}

现在目光回到CollectedHeap::permanent_obj_allocate_no_klass_install方法中,当分配完内存后,接下来就会初始化klassOop._mark标识.如下:

void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass,
                                                           HeapWord* objPtr,
                                                           size_t size) {
  oop obj = (oop)objPtr;

  assert(obj != NULL, "NULL object pointer");
  if (UseBiasedLocking && (klass() != NULL)) {
    obj->set_mark(klass->prototype_header());
  } else {
    // May be bootstrapping
    obj->set_mark(markOopDesc::prototype());
  }
}

注意,此时由于klass() 为 NULL,因此,此处执行如下代码:

obj->set_mark(markOopDesc::prototype());
static markOop prototype() {
	
    return markOop( no_hash_in_place | no_lock_in_place );
  }

注意,此处用到了c++的技巧,由于markOop为指针类型,因此,此处的代码就相当于:

markOopDesc* mark = (markOopDesc*)(no_hash_in_place | no_lock_in_place);

return mark;

此时 klassKlass 状态如下:

klassklass-003

此时目光回到allocate_permanent方法中,此处该执行如下代码:

klassOop new_klass = ((Klass*) result)->as_klassOop();
post_new_init_klass(klass_klass, new_klass, size); 

我们来看,由于此处创建的是klassklass,其申请的内存空间为: oopDesc::header_size() + sizeof(klassKlass)/HeapWordSize

而在Klass::as_klassOop方法中,实现如下:

 klassOop as_klassOop() const {
    // see klassOop.hpp for layout.
    return (klassOop) (((char*) this) - sizeof(klassOopDesc));
  }

则此处new_klass 指向的是属于klassKlass 数据的部分:

klassklass-004

然后我们再来看post_new_init_klass方法的实现:

void Klass_vtbl::post_new_init_klass(KlassHandle& klass,
                                     klassOop new_klass,
                                     int size) const {
  assert(!new_klass->klass_part()->null_vtbl(), "Not a complete klass");
  CollectedHeap::post_allocation_install_obj_klass(klass, new_klass, size);
}


void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass,
                                                   oop obj,
                                                   int size) {

  obj->set_klass(klass());
 }
 
 
 inline void oopDesc::set_klass(klassOop k) {
  // since klasses are promoted no store check is needed
  assert(Universe::is_bootstrapping() || k != NULL, "must be a real klassOop");
  assert(Universe::is_bootstrapping() || k->is_klass(), "not a klassOop");
  if (UseCompressedOops) {
    oop_store_without_check(compressed_klass_addr(), (oop)k);
  } else {
    oop_store_without_check(klass_addr(), (oop) k);
  }
}

这里调用了klass_addr()方法,获得_metadata的地址,进行赋值.如下:

inline oop* oopDesc::klass_addr() {
  // Only used internally and with CMS and will not work with
  // UseCompressedOops
  assert(!UseCompressedOops, "only supported with uncompressed oops");
  return (oop*) &_metadata._klass;
}

由于此处的k是由klass()而来的,由于KlassHandle重载了()操作符,如下:

klassOop    operator () () const               { return obj(); }

klassOop    obj() const                        { return (klassOop)Handle::obj(); }

---- Handle
oop     obj() const                            { return _handle == NULL ? (oop)NULL : *_handle; }

注意,由于这里的KlassHandle是由之前透传的,因此这里最终会将_metadata 赋值为null.如图所示:

klassklass-005

初始化klassOop的数据

这里需要介绍一点的是,JVM内部虽然将klass也封装成立oop,但是klass毕竟也是独立的一种类型,因此也需要记录线程锁等相关标识.如下:

kl->set_prototype_header(markOopDesc::prototype());
kl->set_biased_lock_revocation_count(0);
kl->set_last_biased_lock_bulk_revocation_time(0);

自指

此时回到了klassKlass::create_klass方法中,执行了如下代码:

k->set_klass(k); // point to thyself 自指

此时,klassKlass如图所示:

klassklass-006

此时就完成了klassOop的创建.

总结

创建klassKlass的时序图如下,图中有些步骤省略了…

klassKlass__create_klass

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值