ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

JVM篇-oop-klass模型对类的描叙及类加载&实例化内存申请过程

2021-03-07 20:01:41  阅读:270  来源: 互联网

标签:return 及类 对类 allocate JVM klass NULL class size


一、oop-klass描叙

1、介绍

​ 在JVM内存用到了oop-klass模型来描叙对应的类及对象:oop(ordinary object ponter,普通对象指针),其是用来描叙对象的实例信息。klass,其是JVM内部用来描叙类的信息的,例如Java类的继承信息,成员方法等信息。同时JVM还有一种类型来封装对oop类型的行为-handle。

在这里插入图片描述

2、handle

class Handle VALUE_OBJ_CLASS_SPEC {
 private:
  oop* _handle;

 protected:
  oop     obj() const                            { return _handle == NULL ? (oop)NULL : *_handle; }
  oop     non_null_obj() const                   { assert(_handle != NULL, "resolving NULL handle"); return *_handle; }

 public:
  // Constructors
  Handle()                                       { _handle = NULL; }
  Handle(oop obj);
  Handle(Thread* thread, oop obj);

  // General access
  oop     operator () () const                   { return obj(); }
  oop     operator -> () const                   { return non_null_obj(); }
  bool    operator == (oop o) const              { return obj() == o; }
  bool    operator == (const Handle& h) const          { return obj() == h.obj(); }

  // Null checks
  bool    is_null() const                        { return _handle == NULL; }
  bool    not_null() const                       { return _handle != NULL; }

  // Debugging
  void    print()                                { obj()->print(); }
  Handle(oop *handle, bool dummy)                { _handle = handle; }
  oop* raw_value()                               { return _handle; }
  static oop raw_resolve(oop *handle)            { return handle == NULL ? (oop)NULL : *handle; }
};

​ 可以看到其持有指向oop的指针,同时其的一些方法内部都是去处理的oop

3、oop

class oop {
  oopDesc* _o;

  void register_oop();
  void unregister_oop();

  // friend class markOop;
public:
  void set_obj(const void* p)         {
    raw_set_obj(p);
    if (CheckUnhandledOops) register_oop();
  }
  void raw_set_obj(const void* p)     { _o = (oopDesc*)p; }

  oop()                               { set_obj(NULL); }
  oop(const oop& o)                   { set_obj(o.obj()); }
	......
  oopDesc* obj()  const volatile      { return _o; }

  // General access
  oopDesc*  operator->() const        { return obj(); }
  bool operator==(const oop o) const  { return obj() == o.obj(); }
  bool operator==(void *p) const      { return obj() == p; }
........

oop是持有指向oopDesc的指针,oopDesc就是描叙类信息。

1)、oopDesc

class oopDesc {
  friend class VMStructs;
  friend class JVMCIVMStructs;
 private:
  volatile markOop _mark;
  union _metadata {
    Klass*      _klass;
    narrowKlass _compressed_klass;
  } _metadata;
    ......

这个就是描叙一个对象的基本结构。其中一个是对象头,就是我们一般看并发锁的书的时候说的需要获取的对象头,然后还有一个就是元数据结构_metadata,可以看到其有两个类型_klass&_compressed_klass

Klass* oopDesc::klass() const {
  if (UseCompressedClassPointers) {
    return Klass::decode_klass_not_null(_metadata._compressed_klass);
  } else {
    return _metadata._klass;
  }
}

这里一个就是一般类型,一个就是压缩类型,通过UseCompressedClassPointers参数开启。

typedef class   markOopDesc*                markOop;

typedef class oopDesc*                            oop;
typedef class   instanceOopDesc*            instanceOop;
typedef class   arrayOopDesc*                    arrayOop;
typedef class     objArrayOopDesc*            objArrayOop;
typedef class     typeArrayOopDesc*            typeArrayOop;

​ 这些就是oopDesc的子类。这里我们主要关注两个类型markOopDesc描叙对象的头信息、instanceOopDesc描叙类的实例信息。

2)、markOopDesc

// The markOop describes the header of an object.
//
// Note that the mark is not a real oop but just a word.
// It is placed in the oop hierarchy for historical reasons.
//
// Bit-format of an object header (most significant first, big endian layout below):
//
//  32 bits:
//  --------
//             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
//             size:32 ------------------------------------------>| (CMS free block)
//             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
//  64 bits:
//  --------
//  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
//  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
//  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
//  size:64 ----------------------------------------------------->| (CMS free block)
//
//  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
//  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
//  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
//  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
..........
class markOopDesc: public oopDesc {
 private:
  // Conversion
  uintptr_t value() const { return (uintptr_t) this; }

 public:
  // Constants
  enum { age_bits                 = 4,
         lock_bits                = 2,
         biased_lock_bits         = 1,
         max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
         hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,
         cms_bits                 = LP64_ONLY(1) NOT_LP64(0),
         epoch_bits               = 2
  };

  // The biased locking code currently requires that the age bits be
  // contiguous to the lock bits.
  enum { lock_shift               = 0,
         biased_lock_shift        = lock_bits,
         age_shift                = lock_bits + biased_lock_bits,
         cms_shift                = age_shift + age_bits,
         hash_shift               = cms_shift + cms_bits,
         epoch_shift              = hash_shift
  };
............

​ 通过32位的注释可以看到主要有四种类型normal object一般对象、biased object偏向锁,可以看到其有一个参数JavaThread,指向对应偏向的对象,然后就是CMS free block这个应该就是释放的对象,可以看到其不含任何内容、CMS promoted object这个从名称看猜测其应该是晋升对象,应该是指的晋升到了老年低?(可以看到其已经没有表示年龄age这个属性了)。同时我们可以看到表示年龄的是4位,也就是最大是为15。

3)、instanceOopDesc

// An instanceOop is an instance of a Java Class
// Evaluating "new HashTable()" will create an instanceOop.

class instanceOopDesc : public oopDesc {
 public:
  // aligned header size.
  static int header_size() { return sizeof(instanceOopDesc)/HeapWordSize; }

  // If compressed, the offset of the fields of the instance may not be aligned.
  static int base_offset_in_bytes() {
    // offset computation code breaks if UseCompressedClassPointers
    // only is true
    return (UseCompressedOops && UseCompressedClassPointers) ?
             klass_gap_offset_in_bytes() :
             sizeof(instanceOopDesc);
  }

  static bool contains_field_offset(int offset, int nonstatic_field_size) {
    int base_in_bytes = base_offset_in_bytes();
    return (offset >= base_in_bytes &&
            (offset-base_in_bytes) < nonstatic_field_size * heapOopSize);
  }
};

​ 这个就是表示对应类的实例对象,可以看到这个没有什么额外的内容,然后有个header_size()方法,这个通过注释就是看其头部的大小,因为可以是32位的一个可以是64位的。

4、klass

class Klass : public Metadata {
  friend class VMStructs;
  friend class JVMCIVMStructs;
 ..........

  // Class name.  Instance classes: java/lang/String, etc.  Array classes: [I,
  // [Ljava/lang/String;, etc.  Set to zero for all other kinds of classes.
  Symbol*     _name;
	.........
  // Array of all secondary supertypes
  Array<Klass*>* _secondary_supers;
  // Ordered list of all primary supertypes
  Klass*      _primary_supers[_primary_super_limit];
  // java/lang/Class instance mirroring this class
  oop       _java_mirror;
  // Superclass
  Klass*      _super;
 	..........
  // The VM's representation of the ClassLoader used to load this class.
  // Provide access the corresponding instance java.lang.ClassLoader.
  ClassLoaderData* _class_loader_data;

​ 这个就是在JVM内部描叙Class信息的类,_name就是用来描叙类名称等的内容,这里还有一个oop的类型的_java_mirror,这里在<<揭秘Java虚拟机-JVM设计原理与实现>>这本书的解释是,klass对于类的描叙是提供给JVM内部访问的,而这个_java_mirror是提供给java的。

同时我们可以看到这个类是继承的Metadata元数据:

// This is the base class for an internal Class related metadata
class Metadata : public MetaspaceObj {
class MetaspaceObj {
 public:
  bool is_metaspace_object() const;
  bool is_shared() const;
  void print_address_on(outputStream* st) const;  // nonvirtual address printing

#define METASPACE_OBJ_TYPES_DO(f) \
  f(Unknown) \
  f(Class) \
  f(Symbol) \
  f(TypeArrayU1) \
  f(TypeArrayU2) \
  f(TypeArrayU4) \
  f(TypeArrayU8) \
  f(TypeArrayOther) \
  f(Method) \
  f(ConstMethod) \
  f(MethodData) \
  f(ConstantPool) \
  f(ConstantPoolCache) \
  f(Annotation) \
  f(MethodCounters) \
  f(Deallocated)

​ 可以看到其又是继承的MetaspaceObj,所以其是在分配Metaspace中,同时属于Metaspace还有ConstantPoolConstMethod这些也是在Metaspace

​ 同时Klass类似前面的oopDesc其也有对应的子类,例如InstanceKlassArrayKlass

1)、InstanceKlass

class InstanceKlass: public Klass {
	..........
 protected:
  InstanceKlass(const ClassFileParser& parser, unsigned kind);
	......
  // See "The Java Virtual Machine Specification" section 2.16.2-5 for a detailed description
  // of the class loading & initialization procedure, and the use of the states.
  enum ClassState {
    allocated,                          // allocated (but not yet linked)
    loaded,                             // loaded and inserted in class hierarchy (but not linked yet)
    linked,                             // successfully linked/verified (but not initialized yet)
    being_initialized,                  // currently running class initializer
    fully_initialized,                  // initialized (successfull final state)
    initialization_error                // error happened during initialization
  };

 protected:
  // Annotations for this class
  Annotations*    _annotations;
  // Package this class is defined in
  PackageEntry*   _package_entry;
  // Array classes holding elements of this class.
  Klass* volatile _array_klasses;
  // Constant pool for this class.
  ConstantPool* _constants;
 	.....
  Array<jushort>* _inner_classes;
	..........
  u2              _static_oop_field_count;// number of static oop fields in this klass
  u2              _java_fields_count;    // The number of declared Java fields
  int             _nonstatic_oop_map_size;// size in words of nonstatic oop map blocks

  int             _itable_len;           // length of Java itable (in words)
  // _is_marked_dependent can be set concurrently, thus cannot be part of the
  // _misc_flags.
  bool            _is_marked_dependent;  // used for marking during flushing and deoptimization
  bool            _is_being_redefined;   // used for locking redefinition
		.......
  u2              _misc_flags;
  u2              _minor_version;        // minor version number of class file
  u2              _major_version;        // major version number of class file
  Thread*         _init_thread;          // Pointer to current thread doing initialization (to handle recusive initialization)
  OopMapCache*    volatile _oop_map_cache;   // OopMapCache for all methods in the klass (allocated lazily)
  MemberNameTable* _member_names;        // Member names
  JNIid*          _jni_ids;              // First JNI identifier for static fields in this class
  jmethodID*      volatile _methods_jmethod_ids;  // jmethodIDs corresponding to method_idnum, or NULL if none

​ 这个就是用来描叙类信息的,我们可以看到定义了一个枚举ClassState来表示当前类的加载情况,例如:loaded(加载)、linked(链接)、fully_initialized(完成了类的初始化)。然后还有一些属性例如_annotations注解信息、_constants常量池信息等。

二、类的解析

1、起点 (openjdk\hotspot\src\share\vm\classfile\classLoader.cpp)

instanceKlassHandle ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS) {
	.......
  ResourceMark rm(THREAD);
  HandleMark hm(THREAD);

  const char* const class_name = name->as_C_string();

  EventMark m("loading class %s", class_name);
  ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);

  const char* const file_name = file_name_for_class_name(class_name,
                                                         name->utf8_length());
  assert(file_name != NULL, "invariant");

  ClassLoaderExt::Context context(class_name, file_name, THREAD);

  // Lookup stream for parsing .class file
  ClassFileStream* stream = NULL;
  s2 classpath_index = 0;
  ClassPathEntry* e = NULL;
	.........
  // Load Attempt #2: [jimage | exploded build]
  if (!search_append_only && (NULL == stream)) {
    if (has_jrt_entry()) {
      e = _jrt_entry;
      stream = _jrt_entry->open_stream(file_name, CHECK_NULL);
      if (!context.check(stream, classpath_index)) {
        return NULL;
      }
    } else {
      // Exploded build - attempt to locate class in its defining module's location.
      assert(_exploded_entries != NULL, "No exploded build entries present");
      stream = search_module_entries(_exploded_entries, class_name, file_name, CHECK_NULL);
    }
  }
 	.........
  if (NULL == stream) {
    if (DumpSharedSpaces) {
      tty->print_cr("Preload Warning: Cannot find %s", class_name);
    }
    return NULL;
  }

  stream->set_verify(context.should_verify(classpath_index));

  ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
  Handle protection_domain;

  instanceKlassHandle result = KlassFactory::create_from_stream(stream,
                                                                name,
                                                                loader_data,
                                                                protection_domain,
                                                                NULL, // host_klass
                                                                NULL, // cp_patches
	........
  return context.record_result(name, e, classpath_index, result, THREAD);
}

​ 这个就是去加载解析.class文件:

在这里插入图片描述

​ 可以看到我们目前处理的是BitSet,然后将其读取为stream(ClassFileStream)。

class instanceKlassHandle : public KlassHandle {
 public:
  /* Constructors */
  instanceKlassHandle () : KlassHandle() {}
  instanceKlassHandle (const Klass* k) : KlassHandle(k) {
    assert(k == NULL || is_instanceKlass(k), "illegal type");
  }
  instanceKlassHandle (Thread* thread, const Klass* k) : KlassHandle(thread, k) {
    assert(k == NULL || is_instanceKlass(k), "illegal type");
  }
  /* Access to klass part */
  InstanceKlass*       operator () () const { return (InstanceKlass*)obj(); }
  InstanceKlass*       operator -> () const { return (InstanceKlass*)obj(); }

  debug_only(bool is_instanceKlass(const Klass* k));
};

2)、然后再通过create_from_stream方法来解析:

instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream,
                                                     Symbol* name,
                                                     ClassLoaderData* loader_data,
                                                     Handle protection_domain,
                                                     const InstanceKlass* host_klass,
                                                     GrowableArray<Handle>* cp_patches,
                                                     TRAPS) {
  assert(stream != NULL, "invariant");
  assert(loader_data != NULL, "invariant");
  assert(THREAD->is_Java_thread(), "must be a JavaThread");

  ResourceMark rm;
  HandleMark hm;

  JvmtiCachedClassFileData* cached_class_file = NULL;
		.........
  ClassFileParser parser(stream,
                         name,
                         loader_data,
                         protection_domain,
                         host_klass,
                         cp_patches,
                         ClassFileParser::BROADCAST, // publicity level
                         CHECK_NULL);

  instanceKlassHandle result = parser.create_instance_klass(old_stream != stream, CHECK_NULL);

  if (result.is_null()) {
    return NULL;
  }
		.......
#if INCLUDE_CDS && INCLUDE_JVMTI
  if (DumpSharedSpaces) {
    assert(cached_class_file == NULL, "Sanity");
    // Archive the class stream data into the optional data section
    JvmtiCachedClassFileData *p;
    int len;
    const unsigned char *bytes;
    // event based tracing might set cached_class_file
    if ((bytes = result->get_cached_class_file_bytes()) != NULL) {
      len = result->get_cached_class_file_len();
    } else {
      len = stream->length();
      bytes = stream->buffer();
    }
    p = (JvmtiCachedClassFileData*)MetaspaceShared::optional_data_space_alloc(
                    offset_of(JvmtiCachedClassFileData, data) + len);
    p->length = len;
    memcpy(p->data, bytes, len);
    result->set_archived_class_data(p);
  }
#endif

  return result;
}

​ 这里先解析获取parser,再通过其创建instanceKlassHandle(parser.create_instance_klass(old_stream != stream, CHECK_NULL))。

3)、解析创建InstanceKlass

InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, TRAPS) {
	.........
  InstanceKlass* const ik =
    InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);
  fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL);
	......
  return ik;
}
InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) {
  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_anonymous(),
                                       should_store_fingerprint());

  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()) {
      // mirror
      ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser);
    }
    else if (is_class_loader(class_name, parser)) {
      // class loader
      ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
    }
    else {
      // normal
      ik = new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_misc_kind_other);
    }
  }
  else {
    // reference
    ik = new (loader_data, size, THREAD) InstanceRefKlass(parser);
  }
	......
  // Add all classes to our internal class loader list here,
  // including classes in the bootstrap (NULL) class loader.
  loader_data->add_class(ik, publicize);
  Atomic::inc(&_total_instanceKlass_count);
  return ik;
}

​ 这里就是创建实例KlassInstanceKlass。本次会调用new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_misc_kind_other)

void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw() {
  return Metaspace::allocate(loader_data, word_size, /*read_only*/false,
                             MetaspaceObj::ClassType, THREAD);
}

​ 同时用于这里的类型入参是MetaspaceObj::ClassType,所以是会分配在_class_vsm

然后再来看下fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL):

void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) {
 	.........
  // Fill in information already parsed
  ik->set_should_verify_class(_need_verify);

  // Not yet: supers are done below to support the new subtype-checking fields
  ik->set_class_loader_data(_loader_data);
  ik->set_nonstatic_field_size(_field_info->nonstatic_field_size);
  ik->set_has_nonstatic_fields(_field_info->has_nonstatic_fields);
  ik->set_static_oop_field_count(_fac->count[STATIC_OOP]);
    ..........
  ik->set_name(_class_name);
  if (is_anonymous()) {
    // I am well known to myself
    ik->constants()->klass_at_put(_this_class_index, ik); // eagerly resolve
  }
  ik->set_minor_version(_minor_version);
  ik->set_major_version(_major_version);
  ik->set_has_nonstatic_concrete_methods(_has_nonstatic_concrete_methods);
  ik->set_declares_nonstatic_concrete_methods(_declares_nonstatic_concrete_methods);

  if (_host_klass != NULL) {
    assert (ik->is_anonymous(), "should be the same");
    ik->set_host_klass(_host_klass);
  }

  // Set PackageEntry for this_klass
  oop cl = ik->class_loader();
  Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl));
  ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh());
  ik->set_package(cld, CHECK);
	....
  // check if this class can access its superinterfaces
  check_super_interface_access(ik, CHECK);

  // check if this class overrides any final method
  check_final_method_override(ik, CHECK);
	.....
  // Obtain java.lang.Module
  Handle module_handle(THREAD, JNIHandles::resolve(module_entry->module()));

  // Allocate mirror and initialize static fields
  // The create_mirror() call will also call compute_modifiers()
  java_lang_Class::create_mirror(ik,
                                 _loader_data->class_loader(),
                                 module_handle,
                                 _protection_domain,
                                 CHECK);
	......
  // it's official
  set_klass(ik);
  debug_only(ik->verify();)
}

​ 这个就是填充InstanceKlass的信息,然后我们看下create_mirror方法:

void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader,
                                    Handle module, Handle protection_domain, TRAPS) {
  	.....
  int computed_modifiers = k->compute_modifier_flags(CHECK);
  k->set_modifier_flags(computed_modifiers);
  // Class_klass has to be loaded because it is used to allocate
  // the mirror.
  if (SystemDictionary::Class_klass_loaded()) {
    // Allocate mirror (java.lang.Class instance)
    Handle mirror = InstanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(k, CHECK);

    // Setup indirection from mirror->klass
    if (!k.is_null()) {
      java_lang_Class::set_klass(mirror(), k());
    }

    InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass());
   ...........
}

3)、parser方法解析:

ClassFileParser::ClassFileParser(ClassFileStream* stream,
                                 Symbol* name,
                                 ClassLoaderData* loader_data,
                                 Handle protection_domain,
                                 const InstanceKlass* host_klass,
                                 GrowableArray<Handle>* cp_patches,
                                 Publicity pub_level,
                                 TRAPS) :
 			.......
  // Figure out whether we can skip format checking (matching classic VM behavior)
  if (DumpSharedSpaces) {
    // verify == true means it's a 'remote' class (i.e., non-boot class)
    // Verification decision is based on BytecodeVerificationRemote flag
    // for those classes.
    _need_verify = (stream->need_verify()) ? BytecodeVerificationRemote :
                                              BytecodeVerificationLocal;
  }
  else {
    _need_verify = Verifier::should_verify_for(_loader_data->class_loader(),
                                               stream->need_verify());
  }

  // synch back verification state to stream
  stream->set_verify(_need_verify);

  // Check if verification needs to be relaxed for this class file
  // Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376)
  _relax_verify = relax_format_check_for(_loader_data);

  parse_stream(stream, CHECK);

  post_process_parsed_stream(stream, _cp, CHECK);
}
void ClassFileParser::parse_stream(const ClassFileStream* const stream,
                                   TRAPS) {
  // BEGIN STREAM PARSING
  stream->guarantee_more(8, CHECK);  // magic, major, minor
  // Magic value
  const u4 magic = stream->get_u4_fast();
  // Version numbers
  _minor_version = stream->get_u2_fast();
  _major_version = stream->get_u2_fast();
	..........
  _cp = ConstantPool::allocate(_loader_data,
                               cp_size,
                               CHECK);
  ConstantPool* const cp = _cp;

  parse_constant_pool(stream, cp, cp_size, CHECK);
  // ACCESS FLAGS
  stream->guarantee_more(8, CHECK);  // flags, this_class, super_class, infs_len

  // Access flags
  jint flags;
  // JVM_ACC_MODULE is defined in JDK-9 and later.
  if (_major_version >= JAVA_9_VERSION) {
    flags = stream->get_u2_fast() & (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_MODULE);
  } else {
    flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
  }
	........
  _access_flags.set_flags(flags);

  // This class and superclass
  _this_class_index = stream->get_u2_fast();
 		.....
  Symbol* const class_name_in_cp = cp->klass_name_at(_this_class_index);
  assert(class_name_in_cp != NULL, "class_name can't be null");

  // Update _class_name which could be null previously
  // to reflect the name in the constant pool
  _class_name = class_name_in_cp;

		.........
  // SUPERKLASS
  _super_class_index = stream->get_u2_fast();
  _super_klass = parse_super_class(cp,
                                   _super_class_index,
                                   _need_verify,
                                   CHECK);

  // Interfaces
  _itfs_len = stream->get_u2_fast();
  parse_interfaces(stream,
                   _itfs_len,
                   cp,
                   &_has_nonstatic_concrete_methods,
                   CHECK);
		.......
  // Fields (offsets are filled in later)
  _fac = new FieldAllocationCount();
  parse_fields(stream,
               _access_flags.is_interface(),
               _fac,
               cp,
               cp_size,
               &_java_fields_count,
               CHECK);
	......
  // Methods
  AccessFlags promoted_flags;
  parse_methods(stream,
                _access_flags.is_interface(),
                &promoted_flags,
                &_has_final_method,
                &_declares_nonstatic_concrete_methods,
                CHECK);
	........

  // Additional attributes/annotations
  _parsed_annotations = new ClassAnnotationCollector();
  parse_classfile_attributes(stream, cp, _parsed_annotations, CHECK);
	......
}

​ 这里先会通过ConstantPool::allocate申请常量此的空间,再通过parse_constant_pool(stream, cp, cp_size, CHECK)具体解析,然后解析Methods、Fields这些。

ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) {
  	.......
  int size = ConstantPool::size(length);
	
  return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags);
}
void* MetaspaceObj::operator new(size_t size, ClassLoaderData* loader_data,
                                 size_t word_size, bool read_only,
                                 MetaspaceObj::Type type, TRAPS) throw() {
  // Klass has it's own operator new
  return Metaspace::allocate(loader_data, word_size, read_only, type, THREAD);
}
MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
                              bool read_only, MetaspaceObj::Type type, TRAPS) {
		.......
  MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType;

  // Try to allocate metadata.
  MetaWord* result = loader_data->metaspace_non_null()->allocate(word_size, mdtype);
	.......
  // Zero initialize.	空间清零
  Copy::fill_to_words((HeapWord*)result, word_size, 0);

  return result;
}
public:
 enum MetadataType {
   ClassType,
   NonClassType,
   MetadataTypeCount
 };
 enum MetaspaceType {
   StandardMetaspaceType,
   BootMetaspaceType,
   ROMetaspaceType,
   ReadWriteMetaspaceType,
   AnonymousMetaspaceType,
   ReflectionMetaspaceType
 };

​ 可以看到这里MetadataTypeClassTypeNonClassTypeMetadataTypeCount,这里主要是因为在JVM中又会将MetaspaceType空间再分为两种:

Metaspace* ClassLoaderData::metaspace_non_null() {
  Metaspace* metaspace = load_ptr_acquire(&_metaspace);
  if (metaspace == NULL) {
    MutexLockerEx ml(_metaspace_lock,  Mutex::_no_safepoint_check_flag);
    // Check if _metaspace got allocated while we were waiting for this lock.
    if ((metaspace = _metaspace) == NULL) {
      if (this == the_null_class_loader_data()) {
        assert (class_loader() == NULL, "Must be");
        metaspace = new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType);
      } else if (is_anonymous()) {
        if (class_loader() != NULL) {
          log_trace(class, loader, data)("is_anonymous: %s", class_loader()->klass()->internal_name());
        }
        metaspace = new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType);
      } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
        if (class_loader() != NULL) {
          log_trace(class, loader, data)("is_reflection: %s", class_loader()->klass()->internal_name());
        }
        metaspace = new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType);
      } else {
        metaspace = new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType);
      }
      // Ensure _metaspace is stable, since it is examined without a lock
      OrderAccess::release_store_ptr(&_metaspace, metaspace);
    }
  }
  return metaspace;
}

​ 这里可以看到会创建对应的空间类型new Metaspace

Metaspace::Metaspace(Mutex* lock, MetaspaceType type) {
  initialize(lock, type);
}
void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
  verify_global_initialization();

  // Allocate SpaceManager for metadata objects.
  _vsm = new SpaceManager(NonClassType, lock);

  if (using_class_space()) {
    // Allocate SpaceManager for classes.
    _class_vsm = new SpaceManager(ClassType, lock);
  }

  MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);

  // Allocate chunk for metadata objects
  initialize_first_chunk(type, NonClassType);

  // Allocate chunk for class metadata objects
  if (using_class_space()) {
    initialize_first_chunk(type, ClassType);
  }

  _alloc_record_head = NULL;
  _alloc_record_tail = NULL;
}

​ 可以看到,这里会创建两种空间管理_vsm、如果是Class的话会使用_class_vsm

//  SpaceManager - used by Metaspace to handle allocations
class SpaceManager : public CHeapObj<mtClass> {
  friend class Metaspace;
  friend class Metadebug;

 private:

  // protects allocations
  Mutex* const _lock;

  // Type of metadata allocated.
  Metaspace::MetadataType _mdtype;

​ 使用这个SpaceManager来进行分配管理,可以看到这里是锁的Mutex,用于竞争分配空间。下面我们再来看空间分配:

MetaWord* Metaspace::allocate(size_t word_size, MetadataType mdtype) {
  // DumpSharedSpaces doesn't use class metadata area (yet)
  // Also, don't use class_vsm() unless UseCompressedClassPointers is true.
  if (is_class_space_allocation(mdtype)) {
    return  class_vsm()->allocate(word_size);
  } else {
    return  vsm()->allocate(word_size);
  }
}

可以看到这里会根据类型从不同的vsm中分配:

MetaWord* SpaceManager::allocate(size_t word_size) {
  MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
  size_t raw_word_size = get_allocation_word_size(word_size);
  BlockFreelist* fl =  block_freelists();
  MetaWord* p = NULL;
  // Allocation from the dictionary is expensive in the sense that
  // the dictionary has to be searched for a size.  Don't allocate
  // from the dictionary until it starts to get fat.  Is this
  // a reasonable policy?  Maybe an skinny dictionary is fast enough
  // for allocations.  Do some profiling.  JJJ
  if (fl != NULL && fl->total_size() > allocation_from_dictionary_limit) {
    p = fl->get_block(raw_word_size);
  }
  if (p == NULL) {
    p = allocate_work(raw_word_size);
  }
  return p;
}
MetaWord* SpaceManager::allocate_work(size_t word_size) {
	.....
  // Is there space in the current chunk?
  MetaWord* result = NULL;
	........
  if (current_chunk() != NULL) {
    result = current_chunk()->allocate(word_size);
  }
	.......
  return result;
}
MetaWord* Metachunk::allocate(size_t word_size) {
  MetaWord* result = NULL;
  // If available, bump the pointer to allocate.
  if (free_word_size() >= word_size) {
    result = _top;
    _top = _top + word_size;
  }
  return result;
}

二、类实例的创建

1、起点

​ openjdk\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp

// Allocation

IRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* thread, ConstantPool* pool, int index))
  Klass* k_oop = pool->klass_at(index, CHECK);
  instanceKlassHandle klass (THREAD, k_oop);

  // Make sure we are not instantiating an abstract klass
  klass->check_valid_for_instantiation(true, CHECK);

  // Make sure klass is initialized
  klass->initialize(CHECK);

  // At this point the class may not be fully initialized
  // because of recursive initialization. If it is fully
  // initialized & has_finalized is not set, we rewrite
  // it into its fast version (Note: no locking is needed
  // here since this is an atomic byte write and can be
  // done more than once).
  //
  // Note: In case of classes with has_finalized we don't
  //       rewrite since that saves us an extra check in
  //       the fast version which then would call the
  //       slow version anyway (and do a call back into
  //       Java).
  //       If we have a breakpoint, then we don't rewrite
  //       because the _breakpoint bytecode would be lost.
  oop obj = klass->allocate_instance(CHECK);
  thread->set_vm_result(obj);
IRT_END

​ 我们以这个为起点,看下类实例oop对象是怎样申请空间的:

2、这里首先是klass->initialize(CHECK)

// See "The Virtual Machine Specification" section 2.16.5 for a detailed explanation of the class initialization
// process. The step comments refers to the procedure described in that section.
// Note: implementation moved to static method to expose the this pointer.
void InstanceKlass::initialize(TRAPS) {
  if (this->should_be_initialized()) {
    HandleMark hm(THREAD);
    instanceKlassHandle this_k(THREAD, this);
    initialize_impl(this_k, CHECK);
    // Note: at this point the class may be initialized
    //       OR it may be in the state of being initialized
    //       in case of recursive initialization!
  } else {
    assert(is_initialized(), "sanity check");
  }
}

​ 这里首先是类加载,即instanceKlassHandle对象的创建初始化initialize_impl(this_k, CHECK)

void InstanceKlass::initialize_impl(instanceKlassHandle this_k, TRAPS) {
  // Make sure klass is linked (verified) before initialization
  // A class could already be verified, since it has been reflected upon.
  this_k->link_class(CHECK);
	......
  bool wait = false;

  // refer to the JVM book page 47 for description of steps
  // Step 1
  {
    oop init_lock = this_k->init_lock();
    ObjectLocker ol(init_lock, THREAD, init_lock != NULL);

    Thread *self = THREAD; // it's passed the current thread

    // Step 2
    // If we were to use wait() instead of waitInterruptibly() then
    // we might end up throwing IE from link/symbol resolution sites
    // that aren't expected to throw.  This would wreak havoc.  See 6320309.
    while(this_k->is_being_initialized() && !this_k->is_reentrant_initialization(self)) {
        wait = true;
      ol.waitUninterruptibly(CHECK);
    }
    // Step 3
    if (this_k->is_being_initialized() && this_k->is_reentrant_initialization(self)) {
      DTRACE_CLASSINIT_PROBE_WAIT(recursive, this_k(), -1,wait);
      return;
    }
    // Step 4
    if (this_k->is_initialized()) {
      DTRACE_CLASSINIT_PROBE_WAIT(concurrent, this_k(), -1,wait);
      return;
    }
    // Step 5
    if (this_k->is_in_error_state()) {
      ...........
    }

    // Step 6
    this_k->set_init_state(being_initialized);
    this_k->set_init_thread(self);
  }

  // Step 7
  // Next, if C is a class rather than an interface, initialize it's super class and super
  // interfaces.
  if (!this_k->is_interface()) {
    Klass* super_klass = this_k->super();
    if (super_klass != NULL && super_klass->should_be_initialized()) {
      super_klass->initialize(THREAD);
    }
    // If C implements any interface that declares a non-static, concrete method,
    // the initialization of C triggers initialization of its super interfaces.
    // Only need to recurse if has_nonstatic_concrete_methods which includes declaring and
    // having a superinterface that declares, non-static, concrete methods
    if (!HAS_PENDING_EXCEPTION && this_k->has_nonstatic_concrete_methods()) {
      this_k->initialize_super_interfaces(this_k, THREAD);
    }
	.........
  }

  // Look for aot compiled methods for this klass, including class initializer.
  AOTLoader::load_for_klass(this_k, THREAD);

  // Step 8
  {
        ......
    this_k->call_class_initializer(THREAD);
  }
  // Step 9
  if (!HAS_PENDING_EXCEPTION) {
    this_k->set_initialization_state_and_notify(fully_initialized, CHECK);
        ......
  }
  else {
    // Step 10 and 11
    Handle e(THREAD, PENDING_EXCEPTION);
    CLEAR_PENDING_EXCEPTION;
    // JVMTI has already reported the pending exception
    // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
   	.........
  }
  DTRACE_CLASSINIT_PROBE_WAIT(end, this_k(), -1,wait);
}

这里对应前面的枚举类型就是类的加载过程。加载后,接下来就是oop对象的实例化创建oop obj = klass->allocate_instance(CHECK);:

3、klass->allocate_instance(CHECK)

instanceOop InstanceKlass::allocate_instance(TRAPS) {
  bool has_finalizer_flag = has_finalizer(); // Query before possible GC
  int size = size_helper();  // Query before forming handle.
  KlassHandle h_k(THREAD, this);
  instanceOop i;

  i = (instanceOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
  if (has_finalizer_flag && !RegisterFinalizersAtInit) {
    i = register_finalizer(i, CHECK_NULL);
  }
  return i;
}
typedef class oopDesc*                            oop;
typedef class   instanceOopDesc*            instanceOop;
typedef class   arrayOopDesc*                    arrayOop;
typedef class     objArrayOopDesc*            objArrayOop;
typedef class     typeArrayOopDesc*            typeArrayOop;

​ 这里是通过obj_allocate创建instanceOop实例对象。

4、obj_allocate

​ openjdk\hotspot\src\share\vm\gc\shared\collectedHeap.inline.hpp

oop CollectedHeap::obj_allocate(KlassHandle klass, int size, TRAPS) {
  debug_only(check_for_valid_allocation_state());
  assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed");
  assert(size >= 0, "int won't convert to size_t");
  HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
  post_allocation_setup_obj(klass, obj, size);
  NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
  return (oop)obj;
}

​ 然后再通过common_mem_allocate_init方法进行空间分配及初始化:

HeapWord* CollectedHeap::common_mem_allocate_init(KlassHandle klass, size_t size, TRAPS) {
  HeapWord* obj = common_mem_allocate_noinit(klass, size, CHECK_NULL);
  init_obj(obj, size);
  return obj;
}

5、common_mem_allocate_noinit

HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) {

  HeapWord* result = NULL;
  if (UseTLAB) {
    result = allocate_from_tlab(klass, THREAD, size);
    if (result != NULL) {
      assert(!HAS_PENDING_EXCEPTION,
             "Unexpected exception, will result in uninitialized storage");
      return result;
    }
  }
  bool gc_overhead_limit_was_exceeded = false;
  result = Universe::heap()->mem_allocate(size,
                                          &gc_overhead_limit_was_exceeded);
  if (result != NULL) {
    NOT_PRODUCT(Universe::heap()->
      check_for_non_bad_heap_word_value(result, size));
    assert(!HAS_PENDING_EXCEPTION,
           "Unexpected exception, will result in uninitialized storage");
    THREAD->incr_allocated_bytes(size * HeapWordSize);
    AllocTracer::send_allocation_outside_tlab_event(klass, size * HeapWordSize);

    return result;
  }
	.......
}

​ 这里首先是判断UseTLAB,即是否分配先分配在与线程相关的空间TLAB上(能更快分配,因为如果分配在堆上,由于堆随便那个线程都能申请,所以会加锁,而如果分配在与线程相关的TLAB上,就没有锁竞争,就能更快的分配)

6、allocate_from_tlab

HeapWord* CollectedHeap::allocate_from_tlab(KlassHandle klass, Thread* thread, size_t size) {
  assert(UseTLAB, "should use UseTLAB");

  HeapWord* obj = thread->tlab().allocate(size);
  if (obj != NULL) {
    return obj;
  }
  // Otherwise...
  return allocate_from_tlab_slow(klass, thread, size);
}
// Thread-Local Allocation Buffer (TLAB) support
  ThreadLocalAllocBuffer& tlab()                 { return _tlab; }
inline HeapWord* ThreadLocalAllocBuffer::allocate(size_t size) {
  invariants();
  HeapWord* obj = top();
  if (pointer_delta(end(), obj) >= size) {
    // successful thread-local allocation
#ifdef ASSERT
    // Skip mangling the space corresponding to the object header to
    // ensure that the returned space is not considered parsable by
    // any concurrent GC thread.
    size_t hdr_size = oopDesc::header_size();
    Copy::fill_to_words(obj + hdr_size, size - hdr_size, badHeapWordVal);
#endif // ASSERT
    // This addition is safe because we know that top is
    // at least size below end, so the add can't wrap.
    set_top(obj + size);

    invariants();
    return obj;
  }
  return NULL;
}
HeapWord* top() const                          { return _top; }

​ 这里首先是通过pointer_delta方法看有没有足够的空间分配,有的话就分配,再通过set_top(obj + size);设置新的_top位置。

如果上面这个分配失败,再进入慢分配allocate_from_tlab_slow(KlassHandle klass, Thread* thread, size_t size)

HeapWord* CollectedHeap::allocate_from_tlab_slow(KlassHandle klass, Thread* thread, size_t size) {
	.....
  // Allocate a new TLAB...
  HeapWord* obj = Universe::heap()->allocate_new_tlab(new_tlab_size);
  if (obj == NULL) {
    return NULL;
  }

  AllocTracer::send_allocation_in_new_tlab_event(klass, new_tlab_size * HeapWordSize, size * HeapWordSize);

  if (ZeroTLAB) {
    // ..and clear it.
    Copy::zero_to_words(obj, new_tlab_size);
  } else {
    // ...and zap just allocated object.
#ifdef ASSERT
    // Skip mangling the space corresponding to the object header to
    // ensure that the returned space is not considered parsable by
    // any concurrent GC thread.
    size_t hdr_size = oopDesc::header_size();
    Copy::fill_to_words(obj + hdr_size, new_tlab_size - hdr_size, badHeapWordVal);
#endif // ASSERT
  }
  thread->tlab().fill(obj, obj + size, new_tlab_size);
  return obj;
}

​ 可以看到这里还有一个参数ZeroTLAB来表示是否将分配到空间清零。

​ 下面我们再通过将UseTLAB设置为false来从堆上分配,Universe::heap()->mem_allocate

7、Universe::heap()->mem_allocate

 // The particular choice of collected heap.
  static CollectedHeap* heap() { return _collectedHeap; }
HeapWord* GenCollectedHeap::mem_allocate(size_t size,
                                         bool* gc_overhead_limit_was_exceeded) {
  return gen_policy()->mem_allocate_work(size,
                                         false /* is_tlab */,
                                         gc_overhead_limit_was_exceeded);
}

在这里插入图片描述

​ 可以看到目前的策略是标记清除

HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size,
                                        bool is_tlab,
                                        bool* gc_overhead_limit_was_exceeded) {
  GenCollectedHeap *gch = GenCollectedHeap::heap();
	.............
  HeapWord* result = NULL;

  // Loop until the allocation is satisfied, or unsatisfied after GC.
  for (uint try_count = 1, gclocker_stalled_count = 0; /* return or throw */; try_count += 1) {
    HandleMark hm; // Discard any handles allocated in each iteration.

    // First allocation attempt is lock-free.
    Generation *young = gch->young_gen();
    if (young->should_allocate(size, is_tlab)) {
      result = young->par_allocate(size, is_tlab);
      if (result != NULL) {
        assert(gch->is_in_reserved(result), "result not in heap");
        return result;
      }
    }
    uint gc_count_before;  // Read inside the Heap_lock locked region.
    {
      MutexLocker ml(Heap_lock);
      log_trace(gc, alloc)("GenCollectorPolicy::mem_allocate_work: attempting locked slow path allocation");
      // Note that only large objects get a shot at being
      // allocated in later generations.
      bool first_only = ! should_try_older_generation_allocation(size);

      result = gch->attempt_allocation(size, is_tlab, first_only);
      if (result != NULL) {
        assert(gch->is_in_reserved(result), "result not in heap");
        return result;
      }

      if (GCLocker::is_active_and_needs_gc()) {
        if (is_tlab) {
          return NULL;  // Caller will retry allocating individual object.
        }
        if (!gch->is_maximal_no_gc()) {
          // Try and expand heap to satisfy request.
          result = expand_heap_and_allocate(size, is_tlab);
          // Result could be null if we are out of space.
          if (result != NULL) {
            return result;
          }
        }
	.......  }
}

1)、这里首先是判断是不能再年轻代分配

// First allocation attempt is lock-free.
Generation *young = gch->young_gen();
if (young->should_allocate(size, is_tlab)) {
  result = young->par_allocate(size, is_tlab);
  if (result != NULL) {
    assert(gch->is_in_reserved(result), "result not in heap");
    return result;
  }
}

如果年轻代能分配就通过par_allocate方法去分配空间:

HeapWord* DefNewGeneration::par_allocate(size_t word_size,
                                         bool is_tlab) {
  HeapWord* res = eden()->par_allocate(word_size);
  if (CMSEdenChunksRecordAlways && _old_gen != NULL) {
    _old_gen->sample_eden_chunk();
  }
  return res;
}
// Accessing spaces
  ContiguousSpace* eden() const           { return _eden_space; }
  ContiguousSpace* from() const           { return _from_space; }
  ContiguousSpace* to()   const           { return _to_space;   }
// This version is lock-free.
inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size) {
  do {
    HeapWord* obj = top();
    if (pointer_delta(end(), obj) >= size) {
      HeapWord* new_top = obj + size;
      HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj);
      // result can be one of two:
      //  the old top value: the exchange succeeded
      //  otherwise: the new value of the top is returned.
      if (result == obj) {
        assert(is_aligned(obj) && is_aligned(new_top), "checking alignment");
        return obj;
      }
    } else {
      return NULL;
    }
  } while (true);
}

​ 这里就是在_eden_space区分配,可以看到这里有个注释,现在是没有使用锁的,其是使用Atomic::cmpxchg_ptr操作,即CAS去修改申请的,然后通过while循环。同时上面的DefNewGeneration::par_allocate我们需要注意,其是在eden()申请,并不会如果eden()不够再去from()to()申请。

下面我们看下如果young->should_allocate(size, is_tlab)不满足,通过gch->attempt_allocation(size, is_tlab, first_only)方法申请的过程。

2)、attempt_allocation

MutexLocker ml(Heap_lock);
log_trace(gc, alloc)("GenCollectorPolicy::mem_allocate_work: attempting locked slow path allocation");
// Note that only large objects get a shot at being
// allocated in later generations.
bool first_only = ! should_try_older_generation_allocation(size);

result = gch->attempt_allocation(size, is_tlab, first_only);
if (result != NULL) {
  assert(gch->is_in_reserved(result), "result not in heap");
  return result;
}

​ 可以看到这里会使用锁。

HeapWord* GenCollectedHeap::attempt_allocation(size_t size,
                                               bool is_tlab,
                                               bool first_only) {
  HeapWord* res = NULL;
  if (_young_gen->should_allocate(size, is_tlab)) {
    res = _young_gen->allocate(size, is_tlab);
    if (res != NULL || first_only) {
      return res;
    }
  }
  if (_old_gen->should_allocate(size, is_tlab)) {
    res = _old_gen->allocate(size, is_tlab);
  }
  return res;
}

​ 这里会再次判断_young_gen是否能分配,再次尝试分配。

HeapWord* DefNewGeneration::allocate(size_t word_size, bool is_tlab) {
  // This is the slow-path allocation for the DefNewGeneration.
  // Most allocations are fast-path in compiled code.
  // We try to allocate from the eden.  If that works, we are happy.
  // Note that since DefNewGeneration supports lock-free allocation, we
  // have to use it here, as well.
  HeapWord* result = eden()->par_allocate(word_size);
  if (result != NULL) {
    if (CMSEdenChunksRecordAlways && _old_gen != NULL) {
      _old_gen->sample_eden_chunk();
    }
  } else {
    // If the eden is full and the last collection bailed out, we are running
    // out of heap space, and we try to allocate the from-space, too.
    // allocate_from_space can't be inlined because that would introduce a
    // circular dependency at compile time.
    result = allocate_from_space(word_size);
  }
  return result;
}
HeapWord* DefNewGeneration::allocate_from_space(size_t size) {
  bool should_try_alloc = should_allocate_from_space() || GCLocker::is_active_and_needs_gc();

  // If the Heap_lock is not locked by this thread, this will be called
  // again later with the Heap_lock held.
  bool do_alloc = should_try_alloc && (Heap_lock->owned_by_self() || (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread()));
  HeapWord* result = NULL;
  if (do_alloc) {
    result = from()->allocate(size);
  }
  return result;
}

​ 可以看到这里如果在eden()区分配失败,是可能再在from()区分配的。现在我们看下在老年代的分配:

3)、HeapWord* TenuredGeneration::allocate

HeapWord* TenuredGeneration::allocate(size_t word_size,
                                                 bool is_tlab) {
  assert(!is_tlab, "TenuredGeneration does not support TLAB allocation");
  return _the_space->allocate(word_size);
}
inline HeapWord* OffsetTableContigSpace::allocate(size_t size) {
  HeapWord* res = ContiguousSpace::allocate(size);
  if (res != NULL) {
    _offsets.alloc_block(res, size);
  }
  return res;
}
// This version requires locking.	这种分配是需要锁的
inline HeapWord* ContiguousSpace::allocate_impl(size_t size) {
  assert(Heap_lock->owned_by_self() ||
         (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread()),
         "not locked");
  HeapWord* obj = top();
  if (pointer_delta(end(), obj) >= size) {
    HeapWord* new_top = obj + size;
    set_top(new_top);
    assert(is_aligned(obj) && is_aligned(new_top), "checking alignment");
    return obj;
  } else {
    return NULL;
  }
}

​ 以上就是我们对JVM类对象oopp的空间申请创建的过程这里流程的梳理。

标签:return,及类,对类,allocate,JVM,klass,NULL,class,size
来源: https://blog.csdn.net/qq_25179481/article/details/114495140

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有