Hotspot源码解析-第十九章-ClassLoaderData、符号表、字符串表的初始化

这篇具有很好参考价值的文章主要介绍了Hotspot源码解析-第十九章-ClassLoaderData、符号表、字符串表的初始化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

第十九章-ClassLoaderData初始化

讲解本章先从一张图开始
Hotspot源码解析-第十九章-ClassLoaderData、符号表、字符串表的初始化,Java虚拟机,java

众所周知,Java类的相关信息都是存储在元空间中的,但是是怎么存储的,相信很多读者是不清楚的,这里就不得不涉及到ClassLoaderDataGraph、classLoader、classLoaderData(简称CLD)和Klass的概念及他们四者的关系,这里简单描述下他们的概念,具体细节放到类加载器那一张来讲解。

InstanceKlass(继承自Klass):每个被加载的类在虚拟机中的表示为一个InstanceKlass

ClassLoaderData:类加载器加载类后,存储数据的对象,也就是说被加载的类最终都存储在ClassLoaderData指向的地方,一个CLD可以存入很多被加载的类InstanceKlass,多个InstanceKlass之间通过链表形式存储,且链表头永远是最新加载的类

ClassLoader:类加载器,每个ClassLoader都有一个CLD

ClassLoaderDataGraph:这是CLD的总入口,把所有CLD通过链表管理起来

19.1 根加载器CLD的创建

19.1.1 universe.cpp

19.1.1.1 ClassLoaderData::init_null_class_loader_data
static void init_null_class_loader_data() {
    // 验证重复初始化
    assert(_the_null_class_loader_data == NULL, "cannot initialize twice");
    assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice");

    // 创建ClassLoaderData对象,第一个加载器的参数是NULL,因为在Java中,没有对根加载器的实现,这个是由虚拟机自身来实现加载的,所以相对Java,这是一个NULL,实现看`章节19.1.2`
    _the_null_class_loader_data = new ClassLoaderData((oop)NULL, false, Dependencies());
    // 创建完后,赋值给ClassLoaderDataGraph::_head,表示第一个CLD
    ClassLoaderDataGraph::_head = _the_null_class_loader_data;
    assert(_the_null_class_loader_data->is_the_null_class_loader_data(), "Must be");
    if (DumpSharedSpaces) { // 不涉及多Java进程共享,这一步不会走
      _the_null_class_loader_data->initialize_shared_metaspaces();
    }
  }

19.1.2 classLoaderData.cpp

19.1.2.1 ClassLoaderData构造函数

发现这个构造函数,啥也没做,就是对字段赋初始值

ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) :
  _class_loader(h_class_loader()),
  _is_anonymous(is_anonymous),
  // An anonymous class loader data doesn't have anything to keep
  // it from being unloaded during parsing of the anonymous class.
  // The null-class-loader should always be kept alive.
  _keep_alive(is_anonymous || h_class_loader.is_null()),
  _metaspace(NULL), _unloading(false), _klasses(NULL),
  _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
  _next(NULL), _dependencies(dependencies),
  _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {

  JFR_ONLY(INIT_ID(this);)
}

19.2 符号表和字符串表

先了解下什么是符号表,什么是字符串表?

SymbolTable(符号表):符号是指字节码中产生的各种元数据的utf-8字符表示,所以符号表就是用来存放这些utf-8字符的

StringTable(字符串表):就是存放Java中String对象的,把StringTable表中的数据都可以想像成与Java中String对应

先这么理解吧,在类加载器那一章节会更细致的讲这两个概念。

以下是函数的部分内容,该函数是universe.cpp->universe_init()

// 创建符号表,把它想像成java里的HashMap
SymbolTable::create_table();
// 创建字符串表,把它想像成java里的HashMap
StringTable::create_table();
// 创建包信息表,也可以想像成一个HashMap,包信息用到的时候再讲
ClassLoader::create_package_info_table();

SymbolTable类的定义:
	// 模板类,key为Symbol,value为mtSymbol
    class SymbolTable : public RehashableHashtable<Symbol*, mtSymbol> 
StringTable类的定义:
    // 模板类,key为oop,value为mtSymbol
    class StringTable : public RehashableHashtable<oop, mtSymbol> 
        
SymbolTable:key是Symbol,Symbol可以理解为utf8编码的字符信息
SymbolTable:value是mtSymbol,这是一个枚举值,仅仅表示内存的类型解释,不起实际作用
        
StringTable:key是oop,oop可以理解为指向Java对象的地址(实际上存放的就是Java的String对象的地址)
StringTable:value是mtSymbol,这是一个枚举值,仅仅表示内存的类型解释,不起实际作用

两个表的创建过程都非常简单,但是符号表SymbolTable的创建要复杂些,增加了initialize_symbols初始化符号的操作,代码如下:

static void create_table() {
    assert(_the_table == NULL, "One symbol table allowed.");
    _the_table = new SymbolTable();
    // 预先创建并分配存放符号的内存chunk,symbol_alloc_arena_size = 360K
    initialize_symbols(symbol_alloc_arena_size);
  }

void SymbolTable::initialize_symbols(int arena_alloc_size) {
  // Initialize the arena for global symbols, size passed in depends on CDS.
  if (arena_alloc_size == 0) {
    _arena = new (mtSymbol) Arena(mtSymbol);
  } else {
    // 创建一个Arena对象,细节看`章节19.2.1`
    _arena = new (mtSymbol) Arena(mtSymbol, arena_alloc_size);
  }
}

19.2.1 allocation.cpp

19.2.1.1 Arena构造函数

在JVM运行过程中,会产生大量的符号,为了效率在存储时不可能来一个分配一个,所以需要提前划出一片区域chunk来存储,如果一块chunk不够了,再创建一块,依此类推,Arena就是管理这些chunk的类对象,各chunk之间以链表的形式关联,整个JVM中对内存的管理中,大量使用链表这一数据结构来处理。顺便描述下Arena的几个字段的含义

Chunk *_first; // 第一块 chunk
Chunk *_chunk; // 前在用的 chunk
char *_hwm, *_max; // 当前在用的 chunk 起始点和限制点
size_t _size_in_bytes; // Arena的总大小(所有chunk大小相加)文章来源地址https://www.toymoban.com/news/detail-798362.html

Arena::Arena(MEMFLAGS flag, size_t init_size) : _flags(flag), _size_in_bytes(0)  {
  size_t round_size = (sizeof (char *)) - 1;
  init_size = (init_size+round_size) & ~round_size;
  // 主要看这里,创建了一个init_size大小的chunk块
  _first = _chunk = new (AllocFailStrategy::EXIT_OOM, init_size) Chunk(init_size);
  _hwm = _chunk->bottom();      // 保存 hwm, max,分别指向chunk块可操作的起始点和限制点
  _max = _chunk->top();
  MemTracker::record_new_arena(flag);
  set_size_in_bytes(init_size);
}

到了这里,关于Hotspot源码解析-第十九章-ClassLoaderData、符号表、字符串表的初始化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【OpenCV】第十九章: 视频操作入门

    第十九章: 视频操作入门 一段视频是由很多张静态图片组成的,很多个静态图像组成一段视频。 一个静态图像我们称为一帧,每一帧都是一张静止图像。帧可以以固定的时间间隔从视频中提取,然后对其使用图像处理的方法进行处理,就达到了处理视频的目的。 帧数指每秒

    2024年02月03日
    浏览(44)
  • 第十九章:Linux中安装MySQL

    查看是否安装过 MySQL MySQL 卸载 关闭 ,ysql 服务 查询当前 mysql 安装状态 卸载上述命令【任意一条就行】查询出的已安装程序 注意:务必卸载干净,反复执行 rpm -qa | grep -i mysql 确认是否有卸载残留。 删除 mysql 相关文件 删除 my.cnf 【 MySQL 的配置文件】 检查 /tmp 临时目录权限

    2024年02月13日
    浏览(43)
  • 【Vue3 第十九章】插槽 slot

    数字化管理平台 Vue3+Vite+VueRouter+Pinia+Axios+ElementPlus 权限系统-商城 个人博客地址 在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。这就用到了插槽。 插槽是子组件中的提供给父组件使用的一个占位符,用 slot 表示,父组件可以

    2024年02月09日
    浏览(38)
  • 信安软考 第十九章 操作系统安全保护

    一、操作系统安全概述 1.1 操作系统安全概念与需求 操作系统(operating system),以下都简称OS 操作系统 负责计算机系统的资源管理,支撑和控制各种应用程序运行,为用户提供计算机系统管理接口 。操作系统是构成信息网络系统的核心关键组件,其安全可靠程度决定了计算

    2024年02月06日
    浏览(40)
  • 【Rust】Rust学习 第十九章高级特征

    现在我们已经学习了 Rust 编程语言中最常用的部分。在第二十章开始另一个新项目之前,让我们聊聊一些总有一天你会遇上的部分内容。你可以将本章作为不经意间遇到未知的内容时的参考。本章将要学习的功能在一些非常特定的场景下很有用处。虽然很少会碰到它们,我们

    2024年02月11日
    浏览(43)
  • 【Linux命令行与Shell脚本编程】第十九章 正则表达式

    正则表达式基础 定义BRE模式 扩展正则表达式 在sed和gawk中创建正则表达式,以得到所需的数据。 正则表达式是一种可供Linux工具过滤文本的自定义模板,使用元字符来描述数据流中的一个或多个字符. Linux工具(比如sed或gawk)会在读取数据时使用正则表达式对数据进行模式匹配

    2024年02月13日
    浏览(55)
  • TCP/IP网络编程 第十九章:Windows平台下线程的使用

    要想掌握Windows平台下的线程,应首先理解“内核对象”(Kernel Objects)的概念。如果仅介绍Windows平台下的线程使用技巧,则可以省略相对陌生的内核对象相关内容。但这并不能使各位深入理解Windows平台下的线程。 内核对象的定义 操作系统创建的资源有很多种,如进程、线程

    2024年02月16日
    浏览(51)
  • 第十九章 调用Callout Library函数 - 将 $ZF(-5) 与多个库和许多函数调用一起使用

    对 $ZF(-4,1) 的调用将标注库 inputlibrary.dll 和 outputlibrary.dll 加载到虚拟内存中,并为其返回系统定义的库 ID 。 对 $ZF(-4,3) 的调用使用库 ID 和函数名称来获取库函数的 ID 。返回的函数 ID 实际上是 ZFEntry 表序列号(请参阅上一章中的“创建 ZFEntry 表”)。 第一个循环使用 $ZF(-5

    2024年01月16日
    浏览(41)
  • 【送书福利-第十九期】《C++ Core Guidelines解析》

    😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号:程序员洲洲。 🎈 本文专栏:本文收录于洲洲的《送书福利》系列专栏,该专栏福利多多

    2024年02月08日
    浏览(44)
  • Hotspot源码解析-第二十章-字典表创建和基础类预加载(四)

    20.5.1 systemDictionary.cpp/hpp 20.5.1.1 SystemDictionary::initialize 20.5.1.2 initialize_preloaded_classes 这一部分也用到了很多宏定义,咱们先把宏展开后再来讲解 要使用的宏已经展开了,下面接着讲正题 SystemDictionary::initialize_wk_klasses_until SystemDictionary::initialize_wk_klass

    2024年01月19日
    浏览(33)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包