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

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

顺序表之创建,判满,插入,输出

文章目录 🍊自我介绍🍊创建一个空的顺序表,为结构体在堆区分配空间🍊插入数据🍊输出数据🍊判断顺序表是否满了,满了返回值1,否则返回0🍊main函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞+关注+评论+收藏(一键四连)哦~ 🍊自我介绍   Hello,大家好,我是小珑也要变强(也是小珑),我是易编程·终身成长社群的一名“创始团队·嘉宾”