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

查看openjdk\hotspot\src\share\vm\classfile\classFileParser.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;
}

在openjdk\hotspot\src\share\vm\memory\oopFactory.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);
}

在openjdk\hotspot\src\share\vm\oops\instanceKlassKlass.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();
}

在openjdk\hotspot\src\share\vm\oops\klass.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实例,openjdk\hotspot\src\share\vm\classfile\classFileParser.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;
}

在openjdk\hotspot\src\share\vm\classfile\javaClasses.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类型,openjdk\hotspot\src\share\vm\memory\universe.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();
}
}

openjdk\hotspot\src\share\vm\classfile\javaClasses.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方法;在openjdk\hotspot\src\share\vm\oops\instanceMirrorKlass.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方法,在openjdk\hotspot\src\share\vm\gc_interface\collectedHeap.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());
}
}

最后查看openjdk\hotspot\src\share\vm\runtime\globals.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实例的代码大同小异,从openjdk\hotspot\src\share\vm\oops\instanceMirrorKlass.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;
}

openjdk\hotspot\src\share\vm\gc_interface\collectedHeap.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;
}

在openjdk\hotspot\src\share\vm\gc_interface\collectedHeap.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中

Class实例在堆中还是方法区中?的更多相关文章

  1. (转)java中的方法区

    首先要说明的是,此文章转载自 http://blog.csdn.net/zzhangxiaoyun/article/details/7518917 谢谢作者.是本人认为对方法区解释得比较清楚的一篇文章 ...

  2. JVM中的方法区

    JVM中的方法区 方法区存储什么? 用于存储已被虚拟机加载的类型信息.常量.静态变量.即时编译器编译后的代码缓存 1.类型信息 对每个加载的类型(类class.接口interface.枚举.注解)jv ...

  3. 面试01:解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法

    栈的使用:通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间. 队的使用:通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域 ...

  4. java - 解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法

    通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间: 而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收 ...

  5. 解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法?

    通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间:而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集 ...

  6. 解释内存中的栈(stack)、堆(heap)和方法区(method area) 的用法?

    通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的 现场保存都使用 JVM 中的栈空间:而通过 new 关键字和构造器创建的对象则放在 堆空间,堆是垃圾收集器管理的主要区域,由于现 ...

  7. HotSpot Java虚拟机中的“方法区”“持久代”“元数据区”的关系?

    Sun/Oracle JDK的HotSpot VM中,直到JDK7都有“持久代”(Permanent Generation,简称PermGen).也称为方法区.Oracle JDK8的HotSpot ...

  8. 对象内存空间 在创建对象后 运行时 会把对象的方法放到jvm的方法区中 调用时 将方法拿到栈中 执行完后 这个方法会出栈 然后新的方法方法进栈

  9. Eclipse中的快捷键快速生成常用代码(例如无参、带参构造,set、get方法),以及Java中重要的内存分析(栈、堆、方法区、常量池)

    (一)Eclipse中的快捷键:  ctrl+shift+f自动整理选择的java代码 alt+/ 生成无参构造器或者提升信息 alt+shift+s+o 生成带参构造 ctrl+shift+o快速导 ...

随机推荐

  1. C#设计模式之1:策略模式

    首先需要说明的是该系列的所有内容都是基于headfirst设计模式来描述的.因为我之前也看过不少关于设计模式的书,还是发现这本最好,因为这本书里面给出的例子是最贴切实际的.不说了,开始这个系列吧! 策 ...

  2. 【学亮IT手记】jQuery each()函数用法实例

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...

  3. Day 4-5 序列化 json & pickle &shelve

    序列化: 序列化是指把内存里的数据类型转变成字符串,以使其能存储到硬盘或通过网络传输到远程,因为硬盘或网络传输时只能接受bytes. 反序列化: 把字符转成内存里的数据类型. 用于序列化的两个模块.他 ...

  4. python学习笔记(12)--程序设计方法学

    计算思维: 逻辑思维:推演和演绎 实证思维:实验和验证,引力波->实验 计算思维:设计和构造,计算机为代表,汉诺塔递归. 计算思维特征 抽象和自动化,抽象问题的计算过程,利用计算机自动化求解. ...

  5. 老男孩python学习自修第八天【函数式编程】

    1.可变参数,将传参自动汇总成列表 2.可变参数,将参数自动汇总成字典 实战如下: #!/usr/bin/env python # _*_ coding:UTF-8 _*_ def show(*arg ...

  6. $mount(“#app”)手动挂载

    没有el属性时,证明vue还没绑定到特定的dom上,需要延迟加载,则使用.$mount("")进行手动挂载 https://blog.csdn.net/longzhoufeng/a ...

  7. Vue数组更新及过滤排序

    前面的话 Vue为了增加列表渲染的功能,增加了一组观察数组的方法,而且可以显示一个数组的过滤或排序的副本.本文将详细介绍Vue数组更新及过滤排序 变异方法 Vue 包含一组观察数组的变异方法,它们将会 ...

  8. codeforces467C

    George and Job CodeForces - 467C The new ITone 6 has been released recently and George got really ke ...

  9. codeforces659C

    Tanya and Toys CodeForces - 659C In Berland recently a new collection of toys went on sale. This col ...

  10. winFormToMysql&&几个控件的数据绑定

    运行图: 代码: private void button1_Click(object sender, EventArgs e) { string str = "database=csharp ...