东莞网站建,公司备案号在哪里查询,wordpress目录扫描,外贸福步论坛登录第十九章-ClassLoaderData初始化
讲解本章先从一张图开始
众所周知#xff0c;Java类的相关信息都是存储在元空间中的#xff0c;但是是怎么存储的#xff0c;相信很多读者是不清楚的#xff0c;这里就不得不涉及到ClassLoaderDataGraph、classLoader、classLoaderDataJava类的相关信息都是存储在元空间中的但是是怎么存储的相信很多读者是不清楚的这里就不得不涉及到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表示第一个CLDClassLoaderDataGraph::_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 doesnt 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::leaf1, 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为Symbolvalue为mtSymbolclass SymbolTable : public RehashableHashtableSymbol*, mtSymbol
StringTable类的定义// 模板类key为oopvalue为mtSymbolclass StringTable : public RehashableHashtableoop, mtSymbol SymbolTablekey是SymbolSymbol可以理解为utf8编码的字符信息
SymbolTablevalue是mtSymbol这是一个枚举值仅仅表示内存的类型解释不起实际作用StringTablekey是oopoop可以理解为指向Java对象的地址实际上存放的就是Java的String对象的地址
StringTablevalue是mtSymbol这是一个枚举值仅仅表示内存的类型解释不起实际作用
两个表的创建过程都非常简单但是符号表SymbolTable的创建要复杂些增加了initialize_symbols初始化符号的操作代码如下
static void create_table() {assert(_the_table NULL, One symbol table allowed.);_the_table new SymbolTable();// 预先创建并分配存放符号的内存chunksymbol_alloc_arena_size 360Kinitialize_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大小相加
Arena::Arena(MEMFLAGS flag, size_t init_size) : _flags(flag), _size_in_bytes(0) {size_t round_size (sizeof (char *)) - 1;init_size (init_sizeround_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);
}