Hotspot源码解析-第二十章-字典表创建和基础类预加载(四)

这篇具有很好参考价值的文章主要介绍了Hotspot源码解析-第二十章-字典表创建和基础类预加载(四)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

20.5 字典表创建和基础类预加载

20.5.1 systemDictionary.cpp/hpp

20.5.1.1 SystemDictionary::initialize
void SystemDictionary::initialize(TRAPS) {
  // Allocate arrays
  assert(dictionary() == NULL,
         "SystemDictionary should only be initialized once");
  _sdgeneration        = 0;
  // 创建字典(就是Hash Table)
  _dictionary          = new Dictionary(calculate_systemdictionary_size(PredictedLoadedClassCount));
  // 创建占位符表(就是Hash Table)
  _placeholders        = new PlaceholderTable(_nof_buckets);
  _number_of_modifications = 0;
  // 创建约束表(就是Hash Table)
  _loader_constraints  = new LoaderConstraintTable(_loader_constraint_size);
  // 创建解析错误表(就是Hash Table)
  _resolution_errors   = new ResolutionErrorTable(_resolution_error_size);
   // 创建调用方法符号表(就是Hash Table)
  _invoke_method_table = new SymbolPropertyTable(_invoke_method_size);

  // 分配一个数组来存放系统类加载锁
  _system_loader_lock_obj = oopFactory::new_intArray(0, CHECK);
  // 初始化基础类,细节继续看`章节20.5.1.2`
  initialize_preloaded_classes(CHECK);
#if INCLUDE_JFR
  jfr_event_handler_proxy = SymbolTable::new_permanent_symbol("jdk/jfr/proxy/internal/EventHandlerProxy", CHECK);
#endif // INCLUDE_JFR
}
20.5.1.2 initialize_preloaded_classes

这一部分也用到了很多宏定义,咱们先把宏展开后再来讲解

class SystemDictionary : AllStatic {
  friend class VMStructs;
  friend class SystemDictionaryHandles;

 public:
  enum WKID {
    NO_WKID = 0,

    #define WK_KLASS_ENUM(name, symbol, ignore_o) WK_KLASS_ENUM_NAME(name), WK_KLASS_ENUM_NAME(symbol) = WK_KLASS_ENUM_NAME(name),
    WK_KLASSES_DO(WK_KLASS_ENUM)
    #undef WK_KLASS_ENUM

    WKID_LIMIT,

    FIRST_WKID = NO_WKID + 1
  };
}
// ==============第1块宏:枚举=================
// 宏展开前
#define WK_KLASS_ENUM(name, symbol, ignore_o) WK_KLASS_ENUM_NAME(name), WK_KLASS_ENUM_NAME(symbol) = WK_KLASS_ENUM_NAME(name),
    WK_KLASSES_DO(WK_KLASS_ENUM)
// 宏展开后
// 第1步
   WK_KLASS_ENUM(String_klass,java_lang_String,Pre)
   WK_KLASS_ENUM_NAME(String_klass), WK_KLASS_ENUM_NAME(java_lang_String) = WK_KLASS_ENUM_NAME(String_klass),
// 第2步
   // 前置宏定义
   #define WK_KLASS_ENUM_NAME(kname)    kname##_knum
   String_klass_knum,java_lang_String_knum=String_klass_knum
// 最终 enum WKID 宏展开后
    enum WKID {
      NO_WKID = 0,

      Object_klass_knum,        java_lang_Object_knum = Object_klass_knum,           \
      String_klass_knum,        java_lang_String_knum = String_klass_knum,           \
      Class_klass_knum,         java_lang_Class_knum = Class_klass_knum,             \
      Cloneable_klass_knum,     java_lang_Cloneable_knum = Cloneable_klass_knum,      \
      ClassLoader_klass_knum,   java_lang_ClassLoader_knum = ClassLoader_klass_knum,  \
      Serializable_klass_knum,  java_io_Serializable_knum = Serializable_klass_knum,  \
      System_klass_knum,        java_lang_System_knum = System_klass_knum,            \
      ...

      WKID_LIMIT,

      FIRST_WKID = NO_WKID + 1
  }; 

// ==============第2块宏:函数=================
// 方法的宏展开前
#define WK_KLASS_DECLARE(name, symbol, option) \
    static Klass* name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); } \
    static Klass** name##_addr() {                                                                       \
      return &SystemDictionary::_well_known_klasses[SystemDictionary::WK_KLASS_ENUM_NAME(name)];           \
    }
  WK_KLASSES_DO(WK_KLASS_DECLARE);
  #undef WK_KLASS_DECLARE
// 方法的宏展开后,这里以 Object_klass为例,其他的类推
 static Klass* Object_klass() { 
     return check_klass_pre(_well_known_klasses[Object_klass_knum]); 
 } 
 static Klass** Object_klass_addr() {                                                             
     return &SystemDictionary::_well_known_klasses[SystemDictionary::Object_klass_knum];           
 }

// ==============第3块宏:wk_init_info数组=================
// 宏展开前
static const short wk_init_info[] = {
  #define WK_KLASS_INIT_INFO(name, symbol, option) \
    ( ((int)vmSymbols::VM_SYMBOL_ENUM_NAME(symbol) \
          << SystemDictionary::CEIL_LG_OPTION_LIMIT) \
      | (int)SystemDictionary::option ),
  WK_KLASSES_DO(WK_KLASS_INIT_INFO)
  #undef WK_KLASS_INIT_INFO
  0
};
// 宏展开后,这里还是以 Object_klass 为例,其他的类推
static const short wk_init_info[] = {
    ( ((int)vmSymbols::java_lang_Object_enum << SystemDictionary::CEIL_LG_OPTION_LIMIT) 
      | (int)SystemDictionary::Pre ),
 
  0
};

要使用的宏已经展开了,下面接着讲正题

void SystemDictionary::initialize_preloaded_classes(TRAPS) {
  assert(WK_KLASS(Object_klass) == NULL, "preloaded classes should only be initialized once");
  // Preload commonly used klasses
  WKID scan = FIRST_WKID;
  // first do Object, then String, Class
  if (UseSharedSpaces) {
    initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Object_klass), scan, CHECK);
    // Initialize the constant pool for the Object_class
    InstanceKlass* ik = InstanceKlass::cast(Object_klass());
    ik->constants()->restore_unshareable_info(CHECK);
    initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Class_klass), scan, CHECK);
  } else {
    // 直接看这一步,这个的实现往后看,完成后,那些基础的类就被加载进来了,现在知道为啥我们在Java代码时,基础类(Object/Class/String等)都是不需要额外加载和import进来的,原因就在这
    initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Class_klass), scan, CHECK);
  }

  // 计算String 和 Class 类的字段偏移
  java_lang_String::compute_offsets();
  java_lang_Class::compute_offsets();

  // 给8个基础类型创建它们的Class类型对象(在虚拟机中就是InstanceMirrorKlass)
  Universe::initialize_basic_type_mirrors(CHECK);
  // 修正mirror
  Universe::fixup_mirrors(CHECK);

  // 接下来都是继续加载基础类
  initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Reference_klass), scan, CHECK);

  // Preload ref klasses and set reference types
  InstanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER);
  InstanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass));

  initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Cleaner_klass), scan, CHECK);
  InstanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT);
  InstanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK);
  InstanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL);
  InstanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM);
  InstanceKlass::cast(WK_KLASS(Cleaner_klass))->set_reference_type(REF_CLEANER);

  initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(ReferenceQueue_klass), scan, CHECK);

  // JSR 292 classes
  WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
  WKID jsr292_group_end   = WK_KLASS_ENUM_NAME(VolatileCallSite_klass);
  initialize_wk_klasses_until(jsr292_group_start, scan, CHECK);
  if (EnableInvokeDynamic) {
    initialize_wk_klasses_through(jsr292_group_end, scan, CHECK);
  } else {
    // Skip the JSR 292 classes, if not enabled.
    scan = WKID(jsr292_group_end + 1);
  }

  initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK);
  // 基础类型的包装类的Klass
  _box_klasses[T_BOOLEAN] = WK_KLASS(Boolean_klass);
  _box_klasses[T_CHAR]    = WK_KLASS(Character_klass);
  _box_klasses[T_FLOAT]   = WK_KLASS(Float_klass);
  _box_klasses[T_DOUBLE]  = WK_KLASS(Double_klass);
  _box_klasses[T_BYTE]    = WK_KLASS(Byte_klass);
  _box_klasses[T_SHORT]   = WK_KLASS(Short_klass);
  _box_klasses[T_INT]     = WK_KLASS(Integer_klass);
  _box_klasses[T_LONG]    = WK_KLASS(Long_klass);
  //_box_klasses[T_OBJECT]  = WK_KLASS(object_klass);
  //_box_klasses[T_ARRAY]   = WK_KLASS(object_klass);

  { 
    // 计算加载类时应该使用 loadClass 还是 loadClassInternal
    Method* method = InstanceKlass::cast(ClassLoader_klass())->find_method(vmSymbols::loadClassInternal_name(), vmSymbols::string_class_signature());
    _has_loadClassInternal = (method != NULL);
  }
  {
    // 计算要不要用 checkPackageAccess 方法
    Method* method = InstanceKlass::cast(ClassLoader_klass())->find_method(vmSymbols::checkPackageAccess_name(), vmSymbols::class_protectiondomain_signature());
    _has_checkPackageAccess = (method != NULL);
  }
}

SystemDictionary::initialize_wk_klasses_until

void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id, TRAPS) {
  assert((int)start_id <= (int)limit_id, "IDs are out of order!");
  // 这里就是遍历 WKID 枚举,把基础类都加载一遍,看本章节前面对宏展开的那块
  for (int id = (int)start_id; id < (int)limit_id; id++) {
    assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob");
    int info = wk_init_info[id - FIRST_WKID];
    int sid  = (info >> CEIL_LG_OPTION_LIMIT);
    int opt  = (info & right_n_bits(CEIL_LG_OPTION_LIMIT));
    // 直接看这,这一步完成后,就对基础加载完成了,继续往后看
    initialize_wk_klass((WKID)id, opt, CHECK);
  }

  // 下一次开始的位置换到本次limit的位置
  start_id = limit_id;
}

SystemDictionary::initialize_wk_klass文章来源地址https://www.toymoban.com/news/detail-803495.html

bool SystemDictionary::initialize_wk_klass(WKID id, int init_opt, TRAPS) {
  assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob");
  int  info = wk_init_info[id - FIRST_WKID];
  int  sid  = (info >> CEIL_LG_OPTION_LIMIT);
  // 拿到对应的符号
  Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid);
  // 从数组 _well_known_klasses 中拿到已加载的类
  Klass**    klassp = &_well_known_klasses[id];
  bool must_load = (init_opt < SystemDictionary::Opt);
  if ((*klassp) == NULL) { // 初始klassp肯定是null
    //  下面就是真正类加载的环节了,这个先不讲,留待后续类加载一章来讲
    if (must_load) {
      (*klassp) = resolve_or_fail(symbol, true, CHECK_0); // 加载必须的类
    } else {
      (*klassp) = resolve_or_null(symbol,       CHECK_0); // 加载可选的类
    }
  }
  return ((*klassp) != NULL);
}

到了这里,关于Hotspot源码解析-第二十章-字典表创建和基础类预加载(四)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第二十章 中介者模式

    提示:以下是本篇文章正文内容,下面案例可供参考 闹钟 Alarm 咖啡机 CoffeeMachine TV 窗帘 Curtains

    2024年02月02日
    浏览(33)
  • 第二十章 Unity 渲染管线

    渲染管线是计算机图形中最基础最核心的部分,它是将3D场景显示到2D平面的技术过程。在DirectX课程中,我们就介绍了渲染管线,分为固定渲染管线和可编程渲染管线(Shader)。但是在DirectX 10版本之后统一了渲染架构,就是将顶点着色器和像素着色器被合二为一,成为流处理

    2024年02月07日
    浏览(38)
  • 【OpenCV】第二十章: 图像及视频去背景

    第二十一章: 图像及视频去背景 我们做目标识别、目标检测的时候经常需要去背景,比如车辆检测,就是摄像头拍摄一段车辆行驶视频,统计一下视频里面的车流量,此时我们首先要识别出图片中的车辆才能计数有多少辆车,而要识别车辆就需要先把车辆从图像中分割出来再

    2024年02月02日
    浏览(38)
  • 第二十章 : Spring Boot 集成RabbitMQ(四)

    第二十章 : Spring Boot 集成RabbitMQ(四) 前言 本章知识点:死信队列的定义、场景、作用以及原理、TTL方法的使用以及演示代码示例。 死信队列 定义:什么是死信队列? 在RabbitMQ中,并没有提供真正意义上的延迟队列,但是RabbitMQ可以设置队列、消息的过期时间,当队列或者

    2024年02月04日
    浏览(36)
  • 《HeadFirst设计模式(第二版)》第十章代码——状态模式

             如下图所示,这是一个糖果机的状态机图,要求使用代码实现:  初始版本:         上面的代码很明显极其不利于本维护:比如要添加一个新的状态--每次投入25分钱都能有十分之一的概率获得两个糖果。         很明显上面的代码又要添加一堆if-else了,这种

    2024年02月12日
    浏览(39)
  • 第二十章 分布式任务调度中心&DolphinScheduler架构设计

    1、调度系统概述 1.1、调度系统介绍 含义:在 指定时间协调器 通过分布式执行器并行执行任务。 (1)目标 ​ 分布式环境下处理任务调度,在基于给定的时间点,给定的时间间隔或者给定执行次数自动的执行任务。 (2)作用 分布式调度 作业高可用 最大限度利用资源 (

    2024年02月08日
    浏览(42)
  • 第二十章:ReactFlow的图像处理和计算机视觉

    图像处理和计算机视觉是计算机科学领域中的一个重要分支,涉及到处理、分析和理解图像数据的方法和技术。随着深度学习技术的发展,图像处理和计算机视觉的应用范围不断扩大,已经被广泛应用于人脸识别、自动驾驶、医疗诊断等领域。 ReactFlow是一个用于构建有向无环

    2024年01月20日
    浏览(40)
  • 第二十章 重要HL7操作场景 - 传入消息的双 ACK 序列

    对于进入 Production 的消息,双重确认序列的工作原理如下图所示: 客户端应用程序将消息发送到 Production 中。 入站 ACK 业务服务立即向客户端应用程序发送 1 字节 ACK 。 入站 ACK 业务服务将消息发送到其路由进程。 路由过程通过业务操作将消息路由到其目标。 目标应用程序

    2024年02月13日
    浏览(31)
  • 【框架源码】Spring源码解析之Bean创建源码流程

    问题:Spring中是如何初始化单例bean的? 我们都知道Spring解析xml文件描述成BeanDefinition,解析BeanDefinition最后创建Bean将Bean放入单例池中,那么Spring在创建Bean的这个过程都做了什么。 Spring核心方法refresh()中最最重要的一个方法 finishBeanFactoryInitialization() 方法,该方法负责初始化

    2024年02月09日
    浏览(40)
  • 【源码解析】聊聊SpringBean是如何初始化和创建

    我们知道通过类进行修复不同的属性,比如单例、原型等,而具体的流程是怎么样的呢,这一篇我们开始从源码的视角分析以下。 在刷新容器中有一个方法,其实就是 Bean创建的过程。 而BeanFactory中 preInstantiateSingletons是初始化所有的bean对象的核心流程。 而这里通过去遍历所

    2024年02月05日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包