Android内存结构解析——klass内存分布

作者: 谁动了我的代码 | 来源:发表于2022-11-05 20:34 被阅读0次

.class文件

.class文件是编译.java文件生成的,即所谓的字节码文件。理论上说,不论是什么编程语言,只要经过编译器编译生成的文件符合class文件规范,都可以在JVM上正常运行。这也是如Groovy、Kotlin、Scala……这些语言能够在JVM上运行的本质原因。

想深入学习JVM,字节码文件是避不开的一个知识点。这块知识点相对JVM其他的知识点来说算比较简单的,想深入学习JVM的同学建议补下这块知识。如果你是在看不懂也没关系,我会在VIP课中深入讲解,手动模拟类加载器解析class文件的过程。

instanceKlass类

这是一个C++类,是Java类在JVM中的存在形式,是.class文件经过类加载器子系统加载后生成的。注意:这个类只是Java类在JVM中的存在形式,并不是Class对象。看核心代码

instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,

                                                    ClassLoaderData* loader_data,

                                                    Handle protection_domain,

                                                    KlassHandle host_klass,

                                                    GrowableArray<Handle>* cp_patches,

                                                    TempNewSymbol& parsed_name,

                                                    bool verify,

                                                    TRAPS) {

  ……

    // We can now create the basic Klass* for this klass

    _klass = InstanceKlass::allocate_instance_klass(loader_data,

                                                    vtable_size,

                                                    itable_size,

                                                    info.static_field_size,

                                                    total_oop_map_size2,

                                                    rt,

                                                    access_flags,

                                                    name,

                                                    super_klass(),

                                                    !host_klass.is_null(),

                                                    CHECK_(nullHandle));

    instanceKlassHandle this_klass (THREAD, _klass);

……     

instanceKlass是Klass类的子类,除了完全继承了Klass类的非私有属性外,自己又定义了很多属性用来描述Java类的信息,我们来看看这些属性(标成蓝色的是比较常见的):

  • _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:类的成员属性

Klass类

Klass类是Klass体系的基类,看下继承关系


从类名称上也能看出来,Klass相关类与元空间之间的关系。大多数情况下,Klass的子类是存储在元空间中的。正常情况下在C++中new一个对象,默认是在操作系统内存中的,JVM是如果实现在元空间中分配的呢?答案是重载C++的操作符new,是不是这样呢?看代码

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, CHECK_NULL);

}

Klass类有很多属性,我介绍几个重要的吧:

_layout_helper:如果这个Klass既不是instance也不是array,值为0,如果这个Klass是instance,值为对象的大小,如果这个Klass是array,值为负数。因为数组类型是运行时动态创建的,编译期无法知晓大小。

_java_mirror:这个Klass对于的镜像类的指针

Class对象

JVM并没有将描述Java类元信息的instanceKlass直接暴露给Java程序使用,而是又抽象了一层,即所谓的镜像类:instanceMirrorKlass。jdk8以后,类的静态属性也由存储在instanceKlass实例中转为存放在镜像类的实例中。详情见源码

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

……  

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

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对象是分配在堆上的。


以上就是Android虚拟机中内存结构klass内存解析;这是Android开发中的基础必备;更多Android进阶核心技术学习《Android核心进阶技术》可私:“手册”参与获取免费方式。

结语

总结一下,类加载器将.class文件载入JVM中,parse后生成的是instanceKlass对象,之后会生成这个Klass类对应的镜像类实例,并将Java类中的静态变量初始化后存储在镜像类实例中。这个镜像类就是我们Java代码中的Class对象。

相关文章

  • Android内存结构解析——klass内存分布

    .class文件 .class文件是编译.java文件生成的,即所谓的字节码文件。理论上说,不论是什么编程语言,只...

  • Java并发那些事儿-对象模型

    Java的对象模型 oop-klass model 在JVM的内存结构中,对象是保存在堆内存中,对对象的操作其实是...

  • 好好看,好好学

    Java部分 面向对象 java 内存JVM:图文解析 Java内存结构Java虚拟机内存管理——内存空间划分Ja...

  • Java基础(3)——JVM内存模型

    Java for android 基础知识。 JVM的内存结构分为: 方法区(method) 栈内存(stack)...

  • Android 内存泄漏

    【Android 内存泄漏】 引用: ★★★ 【知识必备】内存泄漏全解析,从此拒绝ANR,让OOM远离你的身边,跟...

  • Android 内存泄漏相关总结

    一.Java内存分配结构复习 1.Java内存分配策略 上一篇Android内存管理分析总结中我们提到了Java内...

  • 2018-03-07

    持续更新,嘿嘿~ Android内存泄漏解析 ​内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使...

  • C++

    排序算法总结 对十二种排序算法进行总结C++ 类内存分布 这里不妨说下 C++ 内存分布结构,我们来看看编译器是怎...

  • JVM 内存结构解析

    1. JVM内存结构 (1) JDK1.7的JVM内存结构 JVM内存结构主要有三大块:堆内存、方法区和栈。 堆内...

  • JVM解析——内存结构

    本系列主要记录笔者在学习 [深入理解Java虚拟机] 一书时的理解我们都知道在Java中,我们并不需要过多的在意内...

网友评论

    本文标题:Android内存结构解析——klass内存分布

    本文链接:https://www.haomeiwen.com/subject/fhxmtdtx.html