Hotspot源码解析-第十七章-虚拟机万物创建(二)

2024-01-11 02:04

本文主要是介绍Hotspot源码解析-第十七章-虚拟机万物创建(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

17.2 GC策略初始化

这一步主要就是确定分代(新生代和老年代)信息、即将分配的Java堆内存的大小,以及针对这些信息的校验

17.2.1 collectorPolicy.cpp&ollectorPolicy.hpp

17.2.1.1 initialize_all
virtual void initialize_all() {// 针对内存分配的大小值做设置和校验CollectorPolicy::initialize_all();// 创建并分配新生代和老年代对象的内存initialize_generations();}// 对应 CollectorPolicy::initialize_all() 函数
virtual void initialize_all() {// 父类中,这是一个纯虚函数(相当于Java里面的抽象函数),只能去子类中找实现,这个函数就是计算即将要创建和分配的内存的对齐值initialize_alignments(); // 对 Java堆大小值的判断和设置initialize_flags();// 对以上两步产生的大小做参数检验initialize_size_info();}// 对应 initialize_alignments() 函数
void MarkSweepPolicy::initialize_alignments() {/** 设置空间和分代对齐(C/C++中分配内存时都需要按着一定大小对齐),对齐的目的就是为了提高内存访问效率,CPU读取内存时不是一个一个字节读的,而是一批字节来读,比如4字节、8字节和64字节等,具体读多少,与CPU的架构、型号、年份有关,现在的机器基本是读64字节(缓存行大小),如果没按对齐规则对齐,就可能读取到的内存是“半包”,这就需要CPU多次读取,效率较低。这里按Generation::GenGrain对齐,这个值定义在generattion.hpp的枚举中enum SomePublicConstants {LogOfGenGrain = 16 ARM32_ONLY(+1),  // 最终得出结果16GenGrain = 1 << LogOfGenGrain    // 1 << 16  ==> 2^16 ==> 64 * k};通过上面的定义可知,_space_alignment和_gen_alignment的值最终就是64*k,也就是按这个值来对齐*/  _space_alignment = _gen_alignment = (uintx)Generation::GenGrain;_heap_alignment = compute_heap_alignment();   // 计算堆空间的对齐值,最终=512 * 4K
}
// 对应 compute_heap_alignment() 函数
size_t CollectorPolicy::compute_heap_alignment() {// 这里就是按CardTable卡表的大小乘以页大小来对齐的,查看源码可以得出,卡表大小card_size=1 << 9 ==> 2^9 ==> 512,最终对齐大小等于:512 * 4K(page_size)size_t alignment = GenRemSet::max_alignment_constraint(GenRemSet::CardTable);if (UseLargePages) { // 用大页,这种情况,忽略alignment = lcm(os::large_page_size(), alignment);}return alignment;
}// 对应 initialize_flags() 函数
void CollectorPolicy::initialize_flags() {// 检验上一步计算的各空间对齐值不为0  assert(_space_alignment != 0, "Space alignment not set up properly");assert(_heap_alignment != 0, "Heap alignment not set up properly");assert(_heap_alignment >= _space_alignment,err_msg("heap_alignment: " SIZE_FORMAT " less than space_alignment: " SIZE_FORMAT,_heap_alignment, _space_alignment));assert(_heap_alignment % _space_alignment == 0,err_msg("heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT,_heap_alignment, _space_alignment));// 检查空间大小限制,InitialHeapSize和MaxHeapSize的值在`章节8.1.1.2`中做了解析,有兴趣的,再回头看看if (FLAG_IS_CMDLINE(MaxHeapSize)) {if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) {vm_exit_during_initialization("Initial heap size set to a larger value than the maximum heap size");}if (_min_heap_byte_size != 0 && MaxHeapSize < _min_heap_byte_size) {vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified");}_max_heap_size_cmdline = true;}// 初始堆大小不能小于1Mif (InitialHeapSize < M) {vm_exit_during_initialization("Too small initial heap");}// 最小堆大小不能小于1Mif (_min_heap_byte_size < M) {vm_exit_during_initialization("Too small minimum heap");}// 用 用户从 -Xmx and -Xms 设置的值,并通过_heap_alignment的大小对齐,得到最小堆大小、初始堆大小、最大堆大小_min_heap_byte_size = align_size_up(_min_heap_byte_size, _heap_alignment);uintx aligned_initial_heap_size = align_size_up(InitialHeapSize, _heap_alignment);uintx aligned_max_heap_size = align_size_up(MaxHeapSize, _heap_alignment);// 值改变了,就写回对应的flags中,这块的设置看`章节8.1.1.3`if (aligned_initial_heap_size != InitialHeapSize) {FLAG_SET_ERGO(uintx, InitialHeapSize, aligned_initial_heap_size);}if (aligned_max_heap_size != MaxHeapSize) {FLAG_SET_ERGO(uintx, MaxHeapSize, aligned_max_heap_size);}if (FLAG_IS_CMDLINE(InitialHeapSize) && _min_heap_byte_size != 0 &&InitialHeapSize < _min_heap_byte_size) {vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified");}if (!FLAG_IS_DEFAULT(InitialHeapSize) && InitialHeapSize > MaxHeapSize) {FLAG_SET_ERGO(uintx, MaxHeapSize, InitialHeapSize);} else if (!FLAG_IS_DEFAULT(MaxHeapSize) && InitialHeapSize > MaxHeapSize) {FLAG_SET_ERGO(uintx, InitialHeapSize, MaxHeapSize);if (InitialHeapSize < _min_heap_byte_size) {_min_heap_byte_size = InitialHeapSize;}}_initial_heap_byte_size = InitialHeapSize;_max_heap_byte_size = MaxHeapSize;FLAG_SET_ERGO(uintx, MinHeapDeltaBytes, align_size_up(MinHeapDeltaBytes, _space_alignment));DEBUG_ONLY(CollectorPolicy::assert_flags();)
}// 分代初始化,默认分成两代(年轻和老年代)
void MarkSweepPolicy::initialize_generations() {// 通过malloc() 库函数分配内存,并得到一个大小为2的分代数组,分别存放年轻代和老年代GenerationSpec,number_of_generations() 这个函数里面写死了返回2_generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, CURRENT_PC,AllocFailStrategy::RETURN_NULL);if (_generations == NULL) {vm_exit_during_initialization("Unable to allocate gen spec");}if (UseParNewGC) {_generations[0] = new GenerationSpec(Generation::ParNew, _initial_gen0_size, _max_gen0_size);} else {// 串行GC的,走这条线,创建新生代GenerationSpec对象,对象内存都是通过malloc()来分配的_generations[0] = new GenerationSpec(Generation::DefNew, _initial_gen0_size, _max_gen0_size);}// 创建老年代GenerationSpec对象_generations[1] = new GenerationSpec(Generation::MarkSweepCompact, _initial_gen1_size, _max_gen1_size);if (_generations[0] == NULL || _generations[1] == NULL) {vm_exit_during_initialization("Unable to allocate gen spec");}
}

17.3 Java堆空间创建

17.3.1 genCollectedHeap.cpp

17.3.1.1 GenCollectedHeap::GenCollectedHeap
GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) :SharedHeap(policy),  // 先调用父类SharedHeap构造函数,看`章节17.3.1.2`_gen_policy(policy), // _gen_policy 赋值为 policy
// 创建一个子任务管理类,管理所有子任务,并赋值给_process_strong_tasks_process_strong_tasks(new SubTasksDone(GCH_PS_NumElements)),_full_collections_completed(0) // _full_collections_completed 赋值
{assert(policy != NULL, "Sanity check");
}
17.3.1.2 sharedHeap.cpp->SharedHeap::SharedHeap
SharedHeap::SharedHeap(CollectorPolicy* policy_) :CollectedHeap(), // 继续调用上级构造函数_collector_policy(policy_),  // 以下为赋值操作_rem_set(NULL),_strong_roots_parity(0),_workers(NULL)
{_sh = this;  // ch is static, should be set only once.// 由于我们讨论的是串行的GC收集器,所以下面这个逻辑不会走,忽略if ((UseParNewGC ||(UseConcMarkSweepGC && (CMSParallelInitialMarkEnabled ||CMSParallelRemarkEnabled)) ||UseG1GC) &&ParallelGCThreads > 0) {_workers = new FlexibleWorkGang("Parallel GC Threads", ParallelGCThreads,/* are_GC_task_threads */true,/* are_ConcurrentGC_threads */false);if (_workers == NULL) {vm_exit_during_initialization("Failed necessary allocation.");} else {_workers->initialize_workers();}}
}
17.3.1.3 collectedHeap.cpp->CollectedHeap::CollectedHeap
CollectedHeap::CollectedHeap() : _n_par_threads(0)  // 赋值
{// 下面这几步就是得到最大数组的大小,用于后期判断一个对象最大占用内存大小的限制const size_t max_len = size_t(arrayOopDesc::max_array_length(T_INT));const size_t elements_per_word = HeapWordSize / sizeof(jint);_filler_array_max_size = align_object_size(filler_array_hdr_size() +max_len / elements_per_word);// 以下都是赋初始值操作_barrier_set = NULL;_is_gc_active = false;_total_collections = _total_full_collections = 0;_gc_cause = _gc_lastcause = GCCause::_no_gc;NOT_PRODUCT(_promotion_failure_alot_count = 0;)NOT_PRODUCT(_promotion_failure_alot_gc_number = 0;)if (UsePerfData) {  // 有关性能数据的,先忽略,以后有机会再单开一个专题来讲EXCEPTION_MARK;// create the gc cause jvmstat counters_perf_gc_cause = PerfDataManager::create_string_variable(SUN_GC, "cause",80, GCCause::to_string(_gc_cause), CHECK);_perf_gc_lastcause =PerfDataManager::create_string_variable(SUN_GC, "lastCause",80, GCCause::to_string(_gc_lastcause), CHECK);}_defer_initial_card_mark = false; // strengthened by subclass in pre_initialize() below.// gc日志事件if (LogEvents) {_gc_heap_log = new GCHeapLog();} else {_gc_heap_log = NULL;}
}

这篇关于Hotspot源码解析-第十七章-虚拟机万物创建(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/592792

相关文章

Window Server2016 AD域的创建的方法步骤

《WindowServer2016AD域的创建的方法步骤》本文主要介绍了WindowServer2016AD域的创建的方法步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、准备条件二、在ServerA服务器中常见AD域管理器:三、创建AD域,域地址为“test.ly”

Python在固定文件夹批量创建固定后缀的文件(方法详解)

《Python在固定文件夹批量创建固定后缀的文件(方法详解)》文章讲述了如何使用Python批量创建后缀为.md的文件夹,生成100个,代码中需要修改的路径、前缀和后缀名,并提供了注意事项和代码示例,... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5.

使用IntelliJ IDEA创建简单的Java Web项目完整步骤

《使用IntelliJIDEA创建简单的JavaWeb项目完整步骤》:本文主要介绍如何使用IntelliJIDEA创建一个简单的JavaWeb项目,实现登录、注册和查看用户列表功能,使用Se... 目录前置准备项目功能实现步骤1. 创建项目2. 配置 Tomcat3. 项目文件结构4. 创建数据库和表5.

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

使用SpringBoot创建一个RESTful API的详细步骤

《使用SpringBoot创建一个RESTfulAPI的详细步骤》使用Java的SpringBoot创建RESTfulAPI可以满足多种开发场景,它提供了快速开发、易于配置、可扩展、可维护的优点,尤... 目录一、创建 Spring Boot 项目二、创建控制器类(Controller Class)三、运行

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步