揭秘java虚拟机(五)类的生命周期


这里主要研究虚拟机对于用户定义的class的处理,对应于 InstanceKlass相关代码

ClassState

按照ClassState这个枚举可以知道有以下几种状态

allocated
loaded
linked
being_initialized
fully_initialized
initialization_error

卸载

虽然在<加密Java虚拟机>中提到类的生命周期还有卸载,但是根据继承关系可以知道InstanceKlass是继承MetaspaceObj,而allocation.hpp里对于MetaspaceObj的delete操作定义如下,看上去这些对象不会被删除

void operator delete(void* p) { ShouldNotCallThis(); }

调用链路

使用 \bnew.*\bInstanceKlass\( 做正则表达式搜索可以发现只有一个地方调用了InstanceKlass的构造方法,那就是InstanceKlass::allocate_instance_klass这个静态方法

SystemDictionary::resolve_super_or_fail
SystemDictionary::resolve_instance_class_or_null_helper
SystemDictionary::resolve_or_null
SystemDictionary::resolve_instance_class_or_null
SystemDictionary::resolve_array_class_or_null
SystemDictionary::load_instance_classs
ClassLoader::load_classs
ClassListParser::load_class_from_source
ClassLoaderExt::load_classs
SystemDictionary::resolve_from_stream
KlassFactory::create_from_stream
SystemDictionary::parse_stream
ClassFileParser::create_instance_klass
KlassFactory::check_shared_class_file_load_hook
InstanceKlass::allocate_instance_klass

allocate

根据下面代码可以看出可能allocate_instance_klass创建父类,也可能是创建子类,这个和继承关系保持一致

InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) {
  bool is_hidden_or_anonymous = parser.is_hidden() || parser.is_unsafe_anonymous();
  const int size = InstanceKlass::size(parser.vtable_size(),
                                       parser.itable_size(),
                                       nonstatic_oop_map_size(parser.total_oop_map_count()),
                                       parser.is_interface(),
                                       parser.is_unsafe_anonymous(),
                                       should_store_fingerprint(is_hidden_or_anonymous));

  const Symbol* const class_name = parser.class_name();
  assert(class_name != NULL, "invariant");
  ClassLoaderData* loader_data = parser.loader_data();
  assert(loader_data != NULL, "invariant");
  InstanceKlass* ik;
  // Allocation
  if (REF_NONE == parser.reference_type()) {
    if (class_name == vmSymbols::java_lang_Class()) {
      ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser);
    }
    else if (is_class_loader(class_name, parser)) {
      ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
    } else {
      ik = new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_kind_other);
    }
  } else {
    ik = new (loader_data, size, THREAD) InstanceRefKlass(parser);
  }
  // Check for pending exception before adding to the loader data and incrementing
  // class count.  Can get OOM here.
  if (HAS_PENDING_EXCEPTION) {
    return NULL;
  }
  return ik;
}

new

注意里面的new和构造函数之间的括号,这里使用了C++的操作符重载,而对于new的重载最典型的应用是placement new,也就是在指定的内存地址创建对象,而这里不完全是.jvm中对于这个new操作的重载定义在allocation.cpp

void* MetaspaceObj::operator new(size_t size, ClassLoaderData* loader_data,
                                 size_t word_size,
                                 MetaspaceObj::Type type, TRAPS) throw() {
  // Klass has it's own operator new
  return Metaspace::allocate(loader_data, word_size, type, THREAD);
}

所以即使new作为关键字,也可以像一个函数一样去定义.在这里可以把构造对象时**new SomeType(someArgs)看作是对new(class SomeType,void* someArgs)**方法的调用.这这个方法的实现可以分为以下几步

SomeType *new(class SomeType,void* someArgs){
	size_t size=sizeof(SomeType);				//获取需要内存大小
	void* out=alloc(size);						//向OS申请内存,对于replacement new可以复用已有内存
	(void *f(void*)) constructor=SomeType.constructor();//获取构造函数
	constructor.apply(out,someArgs);			//调用构造函数完成初始化
	return out;
}

InstanceKlass::InstanceKlass

InstanceKlass.hpp

InstanceKlass的构造方法在instanceKlass.hpp中,代码如下

 public:
  static const KlassID ID = InstanceKlassID;
...
protected:
  InstanceKlass(const ClassFileParser& parser, unsigned kind, KlassID id = ID);
 public:
  InstanceKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }

看上去上面使用了默认参数,至于InstanceKlassID的值是定义在KlassID中的枚举,代码如下

// Klass IDs for all subclasses of Klass
enum KlassID {
  InstanceKlassID,
  InstanceRefKlassID,
  InstanceMirrorKlassID,
  InstanceClassLoaderKlassID,
  TypeArrayKlassID,
  ObjArrayKlassID
};

const uint KLASS_ID_COUNT = 6;

InstanceKlass.cpp

至于InstanceKlass的构造方法的代码如下所示.

InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, KlassID id) :
  Klass(id),
  _nest_members(NULL),
  _nest_host(NULL),
  _permitted_subclasses(NULL),
  _record_components(NULL),
  _static_field_size(parser.static_field_size()),
  _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
  _itable_len(parser.itable_size()),
  _nest_host_index(0),
  _init_state(allocated),
  _reference_type(parser.reference_type()),
  _init_thread(NULL)
{
  set_vtable_length(parser.vtable_size());
  set_kind(kind);
  set_access_flags(parser.access_flags());
  if (parser.is_hidden()) set_is_hidden();
  set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
  set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
                                                    false));

  assert(NULL == _methods, "underlying memory not zeroed?");
  assert(is_instance_klass(), "is layout incorrect?");
  assert(size_helper() == parser.layout_size(), "incorrect size_helper?");

  // Set biased locking bit for all instances of this class; it will be
  // cleared if revocation occurs too often for this type
  if (UseBiasedLocking && BiasedLocking::enabled()) {
    set_prototype_header(markWord::biased_locking_prototype());
  }
}

上面使用了一种称之为初始化列表的cpp特性.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值