JAVA运行时环境逻辑图
一、oop-klass模型
oop-klass模型是JVM底层的数据结构,理解JVM的必要概念
• Klass表示Java类在JVM中的存在形式
• InstanceKlass表示类的元信息
• InstanceMirrorKlass表示类的Class对象
• InstanceRefKlass表示?
• ArrayKlass表示数组类的元信息
• TypeArrayKlass表示基本数组类的元信息
• ObjArrayKlass表示引用数组类的元信息
• oopDesc表示JAVA对象在JVM中的存在形式
• instanceOopDesc表示普通类对象(非数组类对象)
• arrayOopDesc表示数组类对象
• typeArrayOopDesc表示基本数组类对象
• objArrayOopDesc表示引用数组类对象
下面是这几个Klass的继承关系图
下面是这几个oop的继承关系图
1. InstanceKlass
class InstanceKlass: public Klass {
friend class VMStructs;
friend class ClassFileParser;
friend class CompileReplay;
protected:
// Constructor
InstanceKlass(int vtable_len,
int itable_len,
int static_field_size,
int nonstatic_oop_map_size,
ReferenceType rt,
AccessFlags access_flags,
bool is_anonymous);
...
protected:
// Annotations for this class
Annotations* _annotations;
Klass* _array_klasses;
ConstantPool* _constants;Array* inner_classes;
char* _source_debug_extension;
Symbol* _array_name;
int _nonstatic_field_size;
int _static_field_size; // number words used by static fields (oop and non-oop) in this klass
u2 _generic_signature_index;
u2 _source_file_name_index;
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
bool _is_marked_dependent; // used for marking during flushing and deoptimization
bool _has_unloaded_dependent;
enum {
_misc_rewritten = 1 << 0, // methods rewritten.
_misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops
_misc_should_verify_class = 1 << 2, // allow caching of preverification
misc_is_anonymous = 1 << 3, // has embedded host_klass field
misc_is_contended = 1 << 4, // marked with contended annotation
misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods
misc_declares_default_methods = 1 << 6 // directly declares default methods (any access)
};
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)
int vtable_len; // length of Java vtable (in words)
int itable_len; // length of Java itable (in words)
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* methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none
nmethodBucket* dependencies; // list of dependent nmethods
nmethod* osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class
BreakpointInfo* breakpoints; // bpt lists, managed by Method*
GrowableArray<PreviousVersionNode > previous_versions;
JvmtiCachedClassFileData* cached_class_file;
volatile u2 _idnum_allocated_count; change
u1 _init_state; // state of class
u1 _reference_type; // reference type
JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration
NOT_PRODUCT(int _verify_count;) // to avoid redundant verifies
Array<Method> _methods;
Array<Method> _default_methods;
Array<Klass> _local_interfaces;
Array<Klass> transitive_interfaces;
Array* method_ordering;Array* default_vtable_indices;
Array* _fields;
这里贴一下这些成员变量的中文解释
_annotations:保存该类的所有注解
_array_klasses:保存数组元素所关联的klass指针
_constants:保存该类的常量池指针
_inner_classes:保存内部类相关的信息
_array_name:如果该类是数组,就会生成数组类名词,如“[Ljava/lang/String;”
_nonstatic_field_size:非静态字段数量
_static_field_size:静态字段数量
_generic_signature_index:泛型签名在常量池中的索引
_source_file_name_index:文件名在常量池中的索引
_static_oop_field_count:该类包含的静态的引用类型字段个数
_java_fields_count:已声明的Java字段数量
_nonstatic_oop_map_size:非静态oop映射块的大小(以字为单位)
_is_marked_dependent:用于刷新和反优化期间打标
_minor_version:主版本号
_major_version:次版本号
_init_thread:初始化此类的线程
_vtable_len:虚函数表的大小
_itable_len:接口函数表的大小
_oop_map_cache:该类所有方法的OopMapCache(延迟分配)
_member_names:MemberNameTable指针
_jni_ids:存放jni_id单向链表的首地址(什么是jni_id?)
_methods_jmethod_ids:与method_idnum对应的jmethodIDs,如果没有,则为NULL
_dependencies:存放nmethod的Bucket的首地址
_osr_nmethods_head:栈上替换nmethods的链表的首地址
_breakpoints:断点链表首地址
_previous_versions:此实例的前一个版本的有趣部分的数组。请参见下面的PreviousVersionWalker
_cached_class_file:缓存的类文件
_idnum_allocated_count:已经分配的idnum的个数
_init_state:该类的状态,值:allocated(已分配内存但未链接)、loaded(加载并插入到类层次结构中但仍未链接)、linked(验证及链接成功但未初始化)、being_initialized(正在初始化)、fully_initialized(已完成初始化)、initialization_error(初始化出错)
_reference_type:引用类型
_methods:存储该类的所有方法对象的指针的数组指针
_default_methods:存储从接口继承的所有方法对象的指针的数组指针
_local_interfaces:数组指针,存储所有实现的接口的指针
_transitive_interfaces:数组,存储直接实现的接口指针+接口间继承实现的接口指针
_method_ordering:包含类文件中方法的原始顺序的Int数组,JVMTI需要用到
_default_vtable_indices:默认构造方法在虚表中的索引
_fields:类的成员属性
2. InstanceMirrorKlass
class InstanceMirrorKlass: public InstanceKlass {
friend class VMStructs;
friend class InstanceKlass;
private:
static int _offset_of_static_fields;
// Constructor
InstanceMirrorKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous)
: InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous) {}
public:
InstanceMirrorKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
// Type testing
bool oop_is_instanceMirror() const { return true; }
3. InstanceKlass和InstanceMirrorKlass
InstanceKlass和InstanceMirrorKlass
可以看出来
• InstanceKlass中定义了Java运行时环境类所需的所有数据信息,比如 constants 常量池、methods 方法 等(An InstanceKlass is the VM level representation of a Java class. It contains all information needed for at class at execution runtime.)
• InstanceMirrorKlass是InstanceKlass的一个子类
• InstanceMirrorKlass是java.lang.Class类专用的InstanceKlass(An InstanceMirrorKlass is a specialized InstanceKlass for java.lang.Class instances.)
简单总结一下,InstanceKlass包含了Java运行时环境中类所需的所有数据信息,在类加载这一步,类加载器会将.class文件读入类加载器的class content,然后以InstanceKlass的形式写入JVM内存区域的方法区中,而InstanceMirrorKlass是类所对应的Class对象(java.lang.Class)的InstanceKlass
对于InstanceKlass,在Java中,对于所有类,类的内部属性轮廓是不是可以认为是一样的?类都有父类、实现接口、变量、方法、代码块等,而变量和方法也有属性,即可访问性(public、private、protected、default)、静态与非静态,还有数组形式的。无论如何,类的内部属性以及属性的属性,是有限的、可列举的,那么在JVM中以C++代码就可以用一个类来表示,它就是InstanceKlass,这一层是比较好理解的
对于InstanceMirrorKlass的理解,首先需要理解什么是java.lang.Class,我们来看一下这个类的注释吧:Instances
of the class Class represent classes and interfaces in a running Java
application.
翻译过来说,就是类或接口在Java运行时环境中的一个表达方式,再看看java.lang.Class的方法就知道,getConstructors()、getMethods()、getFields()、getDeclaredFields(),这些都是类的内部属性,且对于任何类来说,都可以用形如A.class的方法来获取java.lang.Class,即每个Java类都有一个java.lang.Class,那么在JVM中以C++代码表示,每个类的java.lang.Class就是InstanceMirrorKlass。java.lang.Class也是一个类,InstanceMirrorKlass是InstanceKlass的子类
关于Class对象,JVM并没有将描述Java类元信息的instanceKlass直接暴露给Java程序使用,而是又抽象了一层,即所谓的镜像类:instanceMirrorKlass。jdk8以后,类的静态属性也由存储在instanceKlass实例中转为存放
来看一下parseClassFile方法
instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
TempNewSymbol& parsed_name,
bool verify,
TRAPS) {
……
// Allocate mirror and initialize static fields
java_lang_Class::create_mirror(this_klass, protection_domain, CHECK_(nullHandle));
……
来看一下create_mirror方法,第六行代码:初始化静态字段do_local_static_fields
oop java_lang_Class::create_mirror(KlassHandle k, Handle protection_domain, TRAPS) {
……
Handle mirror = InstanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(k, CHECK_0);
……
// Initialize static fields
InstanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, CHECK_NULL);
……
来看一下allocate_instance方法,从代码中可以看出来,是从堆区分配内存的(CollectedHeap::Class_obj_allocate),所以说Class对象是分配在堆上的
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;
}
总结一下,类加载器将.class文件载入JVM中,parse后生成的是instanceKlass对象,之后会生成这个Klass类对应的镜像类实例,并将Java类中的静态变量初始化后存储在镜像类实例中,这个镜像类就是Java代码中的Class对象
4. InstanceRefKlass
描述java.lang.ref.Reference的子类,这部分的概念与强软弱虚引用、垃圾回收有关系
5. ArrayKlass
在理解了InstanceKlass后,这三个类就很好理解了
• ArrayKlass表示的是数组类的元信息(ArrayKlass is the abstract baseclass for all array classes)
• TypeArrayKlass表示基本数组类的元信息(A TypeArrayKlass is the klass of a typeArray, It contains the type and size of the elements)
• ObjArrayKlass表示引用数组类的元信息(ObjArrayKlass is the klass for objArrays)
class ArrayKlass: public Klass {
friend class VMStructs;
private:
int _dimension; // This is n'th-dimensional array.
Klass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present).
Klass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present).
int _vtable_len; // size of vtable for this klass
oop _component_mirror; // component type, as a java/lang/Cl
TypeArrayKlass
class TypeArrayKlass : public ArrayKlass {
friend class VMStructs;
private:
jint _max_length; // maximum number of elements allowed in an array
// Constructor
TypeArrayKlass(BasicType type, Symbol* name);
static TypeArrayKlass* allocate(ClassLoaderData* loader_data, BasicType type, Symbol* name, TRAPS);
public:
TypeArrayKlass() {} // For dummy objects.
ObjArrayKlass
class ObjArrayKlass : public ArrayKlass {
friend class VMStructs;
private:
Klass* _element_klass; // The klass of the elements of this array type
Klass* _bottom_klass; // The one-dimensional type (InstanceKlass or TypeArrayKlass)
// Constructor
ObjArrayKlass(int n, KlassHandle element_klass, Symbol* name);
static ObjArrayKlass* allocate(ClassLoaderData* loader_data, int n, KlassHandle klass_handle, Symbol* name, TRAPS);
public:
// For dummy objects
ObjArrayKlass() {}
6. oopDesc
oopDesc表示JAVA对象在JVM中的存在形式
class oopDesc {
friend class VMStructs;
private:
volatile markOop _mark;
union _metadata {
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata;
// Fast access to barrier set. Must be initialized.
static BarrierSet* _bs;
public:
markOop mark() const { return _mark; }
markOop* mark_addr() const { return (markOop*) &_mark; }
void set_mark(volatile markOop m) { _mark = m; }
void release_set_mark(markOop m);
markOop cas_set_mark(markOop new_mark, markOop old_mark);
void init_mark();
Klass* klass() const;
Klass* klass_or_null() const volatile;
Klass** klass_addr();
narrowKlass* compressed_klass_addr();
void set_klass(Klass* k);
// For klass field compression
int klass_gap() const;
void set_klass_gap(int z);
// For when the klass pointer is being used as a linked list "next" field.
void set_klass_to_list_ptr(oop k);
oop list_ptr_from_klass();
// size of object header, aligned to platform wordSize
static int header_size() { return sizeof(oopDesc)/HeapWordSize; }
// Returns whether this is an instance of k or an instance of a subclass of k
bool is_a(Klass* k) const;
// Returns the actual oop size of the object
int size();
// Sometimes (for complicated concurrency-related reasons), it is useful
// to be able to figure out the size of an object knowing its klass.
int size_given_klass(Klass* klass);
// type test operations (inlined in oop.inline.h)
bool is_instance() const;
bool is_instanceMirror() const;
bool is_instanceClassLoader() const;
bool is_instanceRef() const;
bool is_array() const;
bool is_objArray() const;
bool is_typeArray() const;
...
instanceOopDesc
instanceOopDesc表示普通类对象(非数组类对象)
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);
}
};
arrayOopDesc
arrayOopDesc表示数组类对象
class objArrayOopDesc : public arrayOopDesc {
friend class ObjArrayKlass;
friend class Runtime1;
friend class psPromotionManager;
friend class CSetMarkOopClosure;
friend class G1ParScanPartialArrayClosure;
template <class T> T* obj_at_addr(int index) const {
assert(is_within_bounds(index), "index out of bounds");
return &((T*)base())[index];
}
private:
// Give size of objArrayOop in HeapWords minus the header
static int array_size(int length) {
const uint OopsPerHeapWord = HeapWordSize/heapOopSize;
assert(OopsPerHeapWord >= 1 && (HeapWordSize % heapOopSize == 0),
"Else the following (new) computation would be in error");
uint res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord;
#ifdef ASSERT
// The old code is left in for sanity-checking; it'll
// go away pretty soon. XXX
// Without UseCompressedOops, this is simply:
// oop->length() * HeapWordsPerOop;
// With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer.
// The oop elements are aligned up to wordSize
const uint HeapWordsPerOop = heapOopSize/HeapWordSize;
uint old_res;
if (HeapWordsPerOop > 0) {
old_res = length * HeapWordsPerOop;
} else {
old_res = align_size_up((uint)length, OopsPerHeapWord)/OopsPerHeapWord;
}
assert(res == old_res, "Inconsistency between old and new.");
#endif // ASSERT
return res;
}
typeArrayOopDesc
typeArrayOopDesc表示基本数组类对象
class typeArrayOopDesc : public arrayOopDesc {
protected:
jchar* char_base() const { return (jchar*) base(T_CHAR); }
jboolean* bool_base() const { return (jboolean*)base(T_BOOLEAN); }
jbyte* byte_base() const { return (jbyte*) base(T_BYTE); }
jint* int_base() const { return (jint*) base(T_INT); }
jlong* long_base() const { return (jlong*) base(T_LONG); }
jshort* short_base() const { return (jshort*) base(T_SHORT); }
jfloat* float_base() const { return (jfloat*) base(T_FLOAT); }
jdouble* double_base() const { return (jdouble*) base(T_DOUBLE); }
friend class TypeArrayKlass;
public:
jbyte* byte_at_addr(int which) const {
assert(is_within_bounds(which), "index out of bounds");
return &byte_base()[which];
}
jboolean* bool_at_addr(int which) const {
assert(is_within_bounds(which), "index out of bounds");
return &bool_base()[which];
}
objArrayOopDesc
objArrayOopDesc表示引用数组类对象
class arrayOopDesc : public oopDesc {
friend class VMStructs;
// Interpreter/Compiler offsets
// Header size computation.
// The header is considered the oop part of this type plus the length.
// Returns the aligned header_size_in_bytes. This is not equivalent to
// sizeof(arrayOopDesc) which should not appear in the code.
static int header_size_in_bytes() {
size_t hs = align_size_up(length_offset_in_bytes() + sizeof(int),
HeapWordSize);
#ifdef ASSERT
// make sure it isn't called before UseCompressedOops is initialized.
static size_t arrayoopdesc_hs = 0;
if (arrayoopdesc_hs == 0) arrayoopdesc_hs = hs;
assert(arrayoopdesc_hs == hs, "header size can't change");
#endif // ASSERT
return (int)hs;
}
public:
// The _length field is not declared in C++. It is allocated after the
// declared nonstatic fields in arrayOopDesc if not compressed, otherwise
// it occupies the second half of the _klass field in oopDesc.
static int length_offset_in_bytes() {
return UseCompressedClassPointers ? klass_gap_offset_in_bytes() :
sizeof(arrayOopDesc);
}