zoukankan      html  css  js  c++  java
  • Class实例在堆中还是方法区中?

    1、JVM中OOP-KLASS模型

    在JVM中,使用了OOP-KLASS模型来表示java对象,即:
    1.jvm在加载class时,创建instanceKlass,表示其元数据,包括常量池、字段、方法等,存放在方法区;instanceKlass是jvm中的数据结构;
    2.在new一个对象时,jvm创建instanceOopDesc,来表示这个对象,存放在堆区,其引用,存放在栈区;它用来表示对象的实例信息,看起来像个指针实际上是藏在指针里的对象;instanceOopDesc对应java中的对象实例;
    3.HotSpot并不把instanceKlass暴露给Java,而会另外创建对应的instanceOopDesc来表示java.lang.Class对象,并将后者称为前者的“Java镜像”,klass持有指向oop引用(_java_mirror便是该instanceKlass对Class对象的引用);
    4.要注意,new操作返回的instanceOopDesc类型指针指向instanceKlass,而instanceKlass指向了对应的类型的Class实例的instanceOopDesc;有点绕,简单说,就是Person实例——>Person的instanceKlass——>Person的Class。

    instanceOopDesc,只包含数据信息,它包含三部分:
    1. 对象头,也叫Mark Word,主要存储对象运行时记录信息,如hashcode, GC分代年龄,锁状态标志,线程ID,时间戳等;
    2. 元数据指针,即指向方法区的instanceKlass实例
    3. 实例数据;
    4. 另外,如果是数组对象,还多了一个数组长度


    2、方法区变迁
    JVM规范虽说编译后代码在方法区,但是不做强制要求,具体要看JVM实现,hotspot将JIT编译生成的代码存放在native memory的CodeCache区域
    jdk6
    Klass元数据信息
    每个类的运行时常量池(字段、方法、类、接口等符号引用)、编译后的代码
    静态字段(无论是否有final)在instanceKlass末尾(位于PermGen内)
    oop 其实就是Class对象实例
    全局字符串常量池StringTable,本质上就是个Hashtable
    符号引用(类型指针是SymbolKlass)


    jdk7
    Klass元数据信息
    每个类的运行时常量池(字段、方法、类、接口等符号引用)、编译后的代码
    静态字段从instanceKlass末尾移动到了java.lang.Class对象(oop)的末尾(位于普通Java heap内)
    oop与全局字符串常量池移到java heap上
    符号引用被移动到native heap中

    jdk8
    移除永久代:
    Klass元数据信息、每个类的运行时常量池、编译后的代码移到了另一块与堆不相连的本地内存————元空间(Metaspace)
    参数控制-XX:MetaspaceSize与-XX:MaxMetaspaceSize。
    关于openjdk移除永久代的相关信息:http://openjdk.java.net/jeps/122

    3、Class实例在堆中还是方法区中?

    JDK6

    查看openjdkhotspotsrcsharevmclassfileclassFileParser.cpp文件的instanceKlassHandle ClassFileParser::parseClassFile方法,在3522行使用oopFactory::new_instanceKlass来创建klassOop;

    klassOop相当于Java中的class,一个klassOop对象包含header、klass_field和Klass

    instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
                                                        Handle class_loader,
                                                        Handle protection_domain,
                                                        KlassHandle host_klass,
                                                        GrowableArray<Handle>* cp_patches,
                                                        symbolHandle& parsed_name,
                                                        bool verify,
                                                        TRAPS) {
     
    
        // 3522
        // We can now create the basic klassOop for this klass
        klassOop ik = oopFactory::new_instanceKlass(vtable_size, itable_size,
                                                    static_field_size,
                                                    total_oop_map_count,
                                                    rt, CHECK_(nullHandle));
        instanceKlassHandle this_klass (THREAD, ik);
    
      // Create new handle outside HandleMark
      instanceKlassHandle this_klass (THREAD, preserve_this_klass);
      debug_only(this_klass->as_klassOop()->verify();)
    
      return this_klass;
    }

     在openjdkhotspotsrcsharevmmemoryoopFactory.cpp中找到这个方法,发现调用了instanceKlassKlass::allocate_instance_klass方法来创建klassOop

    klassOop oopFactory::new_instanceKlass(Symbol* name, int vtable_len, int itable_len,
                                           int static_field_size,
                                           unsigned int nonstatic_oop_map_count,
                                           ReferenceType rt, TRAPS) {
      instanceKlassKlass* ikk = instanceKlassKlass::cast(Universe::instanceKlassKlassObj());
      return ikk->allocate_instance_klass(name, vtable_len, itable_len, static_field_size, nonstatic_oop_map_count, rt, CHECK_NULL);
    }

     在openjdkhotspotsrcsharevmoopsinstanceKlassKlass.cpp中找到allocate_instance_klass方法,发现调用base_create_klass

    klassOop instanceKlassKlass::allocate_instance_klass(Symbol* name, int vtable_len, int itable_len,
                                                int static_field_size,
                                                unsigned nonstatic_oop_map_count,
                                                ReferenceType rt, TRAPS) {
    
      const int nonstatic_oop_map_size =
        instanceKlass::nonstatic_oop_map_size(nonstatic_oop_map_count);
      int size = instanceKlass::object_size(align_object_offset(vtable_len) + align_object_offset(itable_len) + nonstatic_oop_map_size);
    
      // Allocation
      KlassHandle h_this_klass(THREAD, as_klassOop());
      KlassHandle k;
      if (rt == REF_NONE) {
        if (name != vmSymbols::java_lang_Class()) {
          // regular klass
          instanceKlass o;
          k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL);
        } else {
          // Class
          instanceMirrorKlass o;
          k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL);
        }
      } else {
        // reference klass
        instanceRefKlass o;
        k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL);
      }
      
      .....
      
      k()->set_partially_loaded();
      }
      return k();
    }

     在openjdkhotspotsrcsharevmoopsklass.cpp中base_create_klass方法内部直接调用base_create_klass_oop来创建klassOop

    KlassHandle Klass::base_create_klass(KlassHandle& klass, int size,
                                         const Klass_vtbl& vtbl, TRAPS) {
      klassOop ek = base_create_klass_oop(klass, size, vtbl, THREAD);
      return KlassHandle(THREAD, ek);
    }

     allocate_permanent方法默认在PermGen分配内存,instanceKlass对象保存在永久代区域

    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);
    // as_klassOop在klass.hpp文件中 klassOop k
    = kl->as_klassOop(); ......

    return k; }

     总结,从klassOop构建流程看出,JDK1.6中Class实例在方法区,而且和JDK7创建流程有了很大差异

    JDK7

    对于引用类型和数组类型对应的Class实例,openjdkhotspotsrcsharevmclassfileclassFileParser.cpp的instanceKlassHandle ClassFileParser::parseClassFile方法的3615行通过java_lang_Class::create_mirror来创建

    instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
                                                        Handle class_loader,
                                                        Handle protection_domain,
                                                        KlassHandle host_klass,
                                                        GrowableArray<Handle>* cp_patches,
                                                        TempNewSymbol& parsed_name,
                                                        bool verify,
                                                        TRAPS) {
        
        // 3615
        // Allocate mirror and initialize static fields
        java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle));
    
        return this_klass;
    }

     在openjdkhotspotsrcsharevmclassfilejavaClasses.cpp中找到create_mirror方法,看如下发现InstanceMirrorKlass::allocate_instance创建了对象实例,而且实例不是数组时会初始化静态字段

    oop java_lang_Class::create_mirror(KlassHandle k, TRAPS) {
      assert(k->java_mirror() == NULL, "should only assign mirror once");
      // Use this moment of initialization to cache modifier_flags also,
      // to support Class.getModifiers().  Instance classes recalculate
      // the cached flags after the class file is parsed, but before the
      // class is put into the system dictionary.
      int computed_modifiers = k->compute_modifier_flags(CHECK_0);
      k->set_modifier_flags(computed_modifiers);
      if (SystemDictionary::Class_klass_loaded() && (k->oop_is_instance() || k->oop_is_javaArray())) {
        // Allocate mirror (java.lang.Class instance)
        Handle mirror = instanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(k, CHECK_0);
        // Setup indirections
        mirror->obj_field_put(klass_offset,  k());
        k->set_java_mirror(mirror());
    
        instanceMirrorKlass* mk = instanceMirrorKlass::cast(mirror->klass());
        java_lang_Class::set_oop_size(mirror(), mk->instance_size(k));
        java_lang_Class::set_static_oop_field_count(mirror(), mk->compute_static_oop_field_count(mirror()));
    
        // It might also have a component mirror.  This mirror must already exist.
        if (k->oop_is_javaArray()) {
          Handle comp_mirror;
          if (k->oop_is_typeArray()) {
            BasicType type = typeArrayKlass::cast(k->as_klassOop())->element_type();
            comp_mirror = Universe::java_mirror(type);
            assert(comp_mirror.not_null(), "must have primitive mirror");
          } else if (k->oop_is_objArray()) {
            klassOop element_klass = objArrayKlass::cast(k->as_klassOop())->element_klass();
            if (element_klass != NULL
                && (Klass::cast(element_klass)->oop_is_instance() ||
                    Klass::cast(element_klass)->oop_is_javaArray())) {
              comp_mirror = Klass::cast(element_klass)->java_mirror();
              assert(comp_mirror.not_null(), "must have element mirror");
            }
            // else some object array internal to the VM, like systemObjArrayKlassObj
          }
          if (comp_mirror.not_null()) {
            // Two-way link between the array klass and its component mirror:
            arrayKlass::cast(k->as_klassOop())->set_component_mirror(comp_mirror());
            set_array_klass(comp_mirror(), k->as_klassOop());
          }
        } else if (k->oop_is_instance()) {
          // Initialize static fields
          instanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, CHECK_NULL);
        }
        return mirror();
      } else {
        return NULL;
      }
    }

     对于基本数据类型,是JVM内置的Class类型,openjdkhotspotsrcsharevmmemoryuniverse.cpp中initialize_basic_type_mirrors方法便是初始化基本类型的类型实例的,通过调用java_lang_Class::create_basic_type_mirror

    void Universe::initialize_basic_type_mirrors(TRAPS) {
      if (UseSharedSpaces) {
        assert(_int_mirror != NULL, "already loaded");
        assert(_void_mirror == _mirrors[T_VOID], "consistently loaded");
      } else {
    
        assert(_int_mirror==NULL, "basic type mirrors already initialized");
        _int_mirror     =
          java_lang_Class::create_basic_type_mirror("int",    T_INT, CHECK);
        _float_mirror   =
          java_lang_Class::create_basic_type_mirror("float",  T_FLOAT,   CHECK);
        _double_mirror  =
          java_lang_Class::create_basic_type_mirror("double", T_DOUBLE,  CHECK);
        _byte_mirror    =
          java_lang_Class::create_basic_type_mirror("byte",   T_BYTE, CHECK);
        _bool_mirror    =
          java_lang_Class::create_basic_type_mirror("boolean",T_BOOLEAN, CHECK);
        _char_mirror    =
          java_lang_Class::create_basic_type_mirror("char",   T_CHAR, CHECK);
        _long_mirror    =
          java_lang_Class::create_basic_type_mirror("long",   T_LONG, CHECK);
        _short_mirror   =
          java_lang_Class::create_basic_type_mirror("short",  T_SHORT,   CHECK);
        _void_mirror    =
          java_lang_Class::create_basic_type_mirror("void",   T_VOID, CHECK);
    
        _mirrors[T_INT]     = _int_mirror;
        _mirrors[T_FLOAT]   = _float_mirror;
        _mirrors[T_DOUBLE]  = _double_mirror;
        _mirrors[T_BYTE]    = _byte_mirror;
        _mirrors[T_BOOLEAN] = _bool_mirror;
        _mirrors[T_CHAR]    = _char_mirror;
        _mirrors[T_LONG]    = _long_mirror;
        _mirrors[T_SHORT]   = _short_mirror;
        _mirrors[T_VOID]    = _void_mirror;
        //_mirrors[T_OBJECT]  = instanceKlass::cast(_object_klass)->java_mirror();
        //_mirrors[T_ARRAY]   = instanceKlass::cast(_object_klass)->java_mirror();
      }
    }

    openjdkhotspotsrcsharevmclassfilejavaClasses.cpp中的create_basic_type_mirror方法

    oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) {
      // This should be improved by adding a field at the Java level or by
      // introducing a new VM klass (see comment in ClassFileParser)
      oop java_class = instanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance((oop)NULL, CHECK_0);
      if (type != T_VOID) {
        klassOop aklass = Universe::typeArrayKlassObj(type);
        assert(aklass != NULL, "correct bootstrap");
        set_array_klass(java_class, aklass);
      }
      instanceMirrorKlass* mk = instanceMirrorKlass::cast(SystemDictionary::Class_klass());
      java_lang_Class::set_oop_size(java_class, mk->instance_size(oop(NULL)));
      java_lang_Class::set_static_oop_field_count(java_class, 0);
      return java_class;
    }

    对比引用类型和基本数据类型的Class实例创建,发现都是通过instanceOop instanceMirrorKlass::allocate_instance方法;在openjdkhotspotsrcsharevmoopsinstanceMirrorKlass.cpp中可以找到;以下代码就是核心了,通过对JavaObjectsInPerm

    参数的判断来决定Class实例存在方法区还是在堆中。

    instanceOop instanceMirrorKlass::allocate_instance(KlassHandle k, TRAPS) {
      // Query before forming handle.
      int size = instance_size(k);
      KlassHandle h_k(THREAD, as_klassOop());
      instanceOop i;
    
      if (JavaObjectsInPerm) {
        i = (instanceOop) CollectedHeap::permanent_obj_allocate(h_k, size, CHECK_NULL);
      } else {
        assert(ScavengeRootsInCode > 0, "must be");
        i = (instanceOop) CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
      }
    
      return i;
    }

     接下来先看JavaObjectsInPerm为true的情况,CollectedHeap::permanent_obj_allocate方法,在openjdkhotspotsrcsharevmgc_interfacecollectedHeap.inline.hpp中;

    oop CollectedHeap::permanent_obj_allocate(KlassHandle klass, int size, TRAPS) {
      oop obj = permanent_obj_allocate_no_klass_install(klass, size, CHECK_NULL);
      post_allocation_install_obj_klass(klass, obj, size);
      NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value((HeapWord*) obj,
                                                                  size));
      return obj;
    }
    
    oop CollectedHeap::permanent_obj_allocate_no_klass_install(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_permanent_mem_allocate_init(size, CHECK_NULL);
      post_allocation_setup_no_klass_install(klass, obj, size);
      NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
      return (oop)obj;
    }

     最终调用的是common_permanent_mem_allocate_init方法中的common_permanent_mem_allocate_noinit方法来创建实例

    HeapWord* CollectedHeap::common_permanent_mem_allocate_init(size_t size, TRAPS) {
     // 内存空间的分配 HeapWord* obj = common_permanent_mem_allocate_noinit(size, CHECK_NULL); // 对象的初始化
    init_obj(obj, size); return obj; }

     从common_permanent_mem_allocate_noinit方法的名字,和内存溢出的异常"PermGen space"可以看出最后创建oop实例是在方法区中

    // Need to investigate, do we really want to throw OOM exception here?
    HeapWord* CollectedHeap::common_permanent_mem_allocate_noinit(size_t size, TRAPS) {
      if (HAS_PENDING_EXCEPTION) {
        NOT_PRODUCT(guarantee(false, "Should not allocate with exception pending"));
        return NULL;  // caller does a CHECK_NULL too
      }
    
    #ifdef ASSERT
      if (CIFireOOMAt > 0 && THREAD->is_Compiler_thread() &&
          ++_fire_out_of_memory_count >= CIFireOOMAt) {
        // For testing of OOM handling in the CI throw an OOM and see how
        // it does.  Historically improper handling of these has resulted
        // in crashes which we really don't want to have in the CI.
        THROW_OOP_0(Universe::out_of_memory_error_perm_gen());
      }
    #endif
    
      HeapWord* result = Universe::heap()->permanent_mem_allocate(size);
      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");
        return result;
      }
      // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
      report_java_out_of_memory("PermGen space");
    
      if (JvmtiExport::should_post_resource_exhausted()) {
        JvmtiExport::post_resource_exhausted(
            JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR,
            "PermGen space");
      }
    
      THROW_OOP_0(Universe::out_of_memory_error_perm_gen());
    }

     再看JavaObjectsInPerm参数为false的情况,仍然是在collectedHeap.inline.hpp文件中,发现调用了common_mem_allocate_init,接着又调用了common_mem_allocate_noinit

    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(size, false, CHECK_NULL);
      post_allocation_setup_obj(klass, obj, size);
      NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
      return (oop)obj;
    }
    HeapWord* CollectedHeap::common_mem_allocate_init(size_t size, bool is_noref, TRAPS) {
    // 内存空间的分配 HeapWord
    * obj = common_mem_allocate_noinit(size, is_noref, CHECK_NULL);
    // 对象的初始化  init_obj(obj, size);
    return obj; }

     从common_mem_allocate_noinit方法的名字,和内存溢出的异常"Java heap space"可以创建oop实例是在java heap中

    HeapWord* CollectedHeap::common_mem_allocate_noinit(size_t size, bool is_noref, TRAPS) {
    
      // Clear unhandled oops for memory allocation.  Memory allocation might
      // not take out a lock if from tlab, so clear here.
      CHECK_UNHANDLED_OOPS_ONLY(THREAD->clear_unhandled_oops();)
    
      if (HAS_PENDING_EXCEPTION) {
        NOT_PRODUCT(guarantee(false, "Should not allocate with exception pending"));
        return NULL;  // caller does a CHECK_0 too
      }
    
      // We may want to update this, is_noref objects might not be allocated in TLABs.
      HeapWord* result = NULL;
      if (UseTLAB) {
        result = CollectedHeap::allocate_from_tlab(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,
                                              is_noref,
                                              false,
                                              &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);
        return result;
      }
    
    
      if (!gc_overhead_limit_was_exceeded) {
        // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
        report_java_out_of_memory("Java heap space");
    
        if (JvmtiExport::should_post_resource_exhausted()) {
          JvmtiExport::post_resource_exhausted(
            JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP,
            "Java heap space");
        }
    
        THROW_OOP_0(Universe::out_of_memory_error_java_heap());
      } else {
        // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
        report_java_out_of_memory("GC overhead limit exceeded");
    
        if (JvmtiExport::should_post_resource_exhausted()) {
          JvmtiExport::post_resource_exhausted(
            JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP,
            "GC overhead limit exceeded");
        }
    
        THROW_OOP_0(Universe::out_of_memory_error_gc_overhead_limit());
      }
    }

     最后查看openjdkhotspotsrcsharevm untimeglobals.hpp文件,发现JavaObjectsInPerm的值是定义为false的

      develop(bool, JavaObjectsInPerm, false,                                   
              "controls whether Classes and interned Strings are allocated"     
              "in perm.  This purely intended to allow debugging issues"        
              "in production.")       

    总结:JDK7创建Class实例存在堆中;因为JDK7中JavaObjectsInPerm参数值固定为false。

    JDK8

    JDK8和JDK7创建Class实例的代码大同小异,从openjdkhotspotsrcsharevmoopsinstanceMirrorKlass.cpp中的instanceOop InstanceMirrorKlass::allocate_instance方法开始才有了区别;
    不在判断JavaObjectsInPerm参数,因为jdk8已经去除了永久代,取而代之的值MetaSpace。这里直接调用CollectedHeap::Class_obj_allocate

    instanceOop InstanceMirrorKlass::allocate_instance(KlassHandle k, TRAPS) {
      // Query before forming handle.
      int size = instance_size(k);
      KlassHandle h_k(THREAD, this);
      instanceOop i = (instanceOop) CollectedHeap::Class_obj_allocate(h_k, size, k, CHECK_NULL);
      return i;
    }

     openjdkhotspotsrcsharevmgc_interfacecollectedHeap.cpp中找到CollectedHeap::Class_obj_allocate

    oop CollectedHeap::Class_obj_allocate(KlassHandle klass, int size, KlassHandle real_klass, TRAPS) {
     
      HeapWord* obj;
      obj = common_mem_allocate_init(real_klass, size, CHECK_NULL);
      oop mirror = (oop)obj;
    
      java_lang_Class::set_oop_size(mirror, size);
    
      // Setup indirections
      if (!real_klass.is_null()) {
        java_lang_Class::set_klass(mirror, real_klass());
        real_klass->set_java_mirror(mirror);
      }
    
      InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass());
      assert(size == mk->instance_size(real_klass), "should have been set");
    
      // notify jvmti and dtrace
      post_allocation_notify(klass, (oop)obj);
    
      return mirror;
    }

     在openjdkhotspotsrcsharevmgc_interfacecollectedHeap.inline.hpp中找到common_mem_allocate_init发现调用了common_mem_allocate_noinit

    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;
    }

    内存溢出的异常"Java heap space"可以看出JDK8创建的Class实例最终在堆中

    HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) {
    
      // Clear unhandled oops for memory allocation.  Memory allocation might
      // not take out a lock if from tlab, so clear here.
      CHECK_UNHANDLED_OOPS_ONLY(THREAD->clear_unhandled_oops();)
    
      if (HAS_PENDING_EXCEPTION) {
        NOT_PRODUCT(guarantee(false, "Should not allocate with exception pending"));
        return NULL;  // caller does a CHECK_0 too
      }
    
      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;
      }
    
    
      if (!gc_overhead_limit_was_exceeded) {
        // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
        report_java_out_of_memory("Java heap space");
    
        if (JvmtiExport::should_post_resource_exhausted()) {
          JvmtiExport::post_resource_exhausted(
            JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP,
            "Java heap space");
        }
    
        THROW_OOP_0(Universe::out_of_memory_error_java_heap());
      } else {
        // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
        report_java_out_of_memory("GC overhead limit exceeded");
    
        if (JvmtiExport::should_post_resource_exhausted()) {
          JvmtiExport::post_resource_exhausted(
            JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP,
            "GC overhead limit exceeded");
        }
    
        THROW_OOP_0(Universe::out_of_memory_error_gc_overhead_limit());
      }
    }

     总结:JDK8移除了永久代,转而使用元空间来实现方法区,创建的Class实例在java heap中

  • 相关阅读:
    Windows 无法启动xx服务 错误1053:服务没有及时响应启动或控制请求
    Nginx之解压编译安装-yellowcong
    SqlServer中的数据类型UniqueIdentifier
    Android利用Volley异步载入数据完整具体演示样例(二)
    蓝桥杯——历年真题之带分数
    联想教育应用使用说明(7.6版本号)——第4章 网络控制工具的使用
    oracle入门学习笔记
    Asp.Net实现JS前台带箭头的流程图方法总结!(个人笔记,信息不全)
    到底什么是RPC?
    Codeforces Round #336 (Div. 2) 608C Chain Reaction(dp)
  • 原文地址:https://www.cnblogs.com/xy-nb/p/6773051.html
Copyright © 2011-2022 走看看