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

17.4 Java堆空间内存分配

分配Java堆内存前,我们先通过两图来了解下C堆、Java堆、内核空间、native本地空间的关系。

1、从图17-1来看,Java堆的分配其实就是从Java进程运行时堆中选中一块内存区域来映射

2、从图17-2,可以看中各内存空间的关系,当然实际的内存区域比这个复杂的多,这里只是概括说明

图17-1
在这里插入图片描述

图17-2
在这里插入图片描述

17.4.1 genCollectedHeap.cpp

17.4.1.1 GenCollectedHeap::initialize
jint GenCollectedHeap::initialize() {// 这一步只是对c2编译器开通使用时,做一些参数赋值操作,这里就不展开讲CollectedHeap::pre_initialize();// 这里获取分代数_n_gens,就是2int i;_n_gens = gen_policy()->number_of_generations();// 保证2个值相等wordSize和HeapWordSize分别是在操作系统和Java堆中代表一个字word占用内存的大小,这两个值必然相同,否则出错guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize");// Java堆的对齐值,这个在`章节17.2.1.1`中有介绍size_t gen_alignment = Generation::GenGrain;// 获取分代对象数组,这个在`章节17.2.1.1`中有介绍,数组元素就2个,索引0元素表示年轻代,索引1元素表示老年代_gen_specs = gen_policy()->generations();// 分别遍历新生代和老年代,并设置各自分代的空间大小(初始值和最大值),同时确保内存对齐for (i = 0; i < _n_gens; i++) {_gen_specs[i]->align(gen_alignment);}// 下面才是给Java堆分配空间char* heap_address;size_t total_reserved = 0;int n_covered_regions = 0;ReservedSpace heap_rs;// 这是最外层Java堆的内存对齐值size_t heap_alignment = collector_policy()->heap_alignment();// 分配java堆内存,看`章节17.4.1.2`heap_address = allocate(heap_alignment, &total_reserved,&n_covered_regions, &heap_rs);if (!heap_rs.is_reserved()) {vm_shutdown_during_initialization("Could not reserve enough space for object heap");return JNI_ENOMEM;}// 将分配的Java堆内存,用 MemRegion 内存区域对象管理起来_reserved = MemRegion((HeapWord*)heap_rs.base(),(HeapWord*)(heap_rs.base() + heap_rs.size()));// 参数赋值_reserved.set_word_size(0);_reserved.set_start((HeapWord*)heap_rs.base()); // Java堆内存的首地址size_t actual_heap_size = heap_rs.size(); // Java堆内存大小// Java堆内存的限制地址,也就是不能超过这条线_reserved.set_end((HeapWord*)(heap_rs.base() + actual_heap_size)); // 接下来就是创建记忆集、卡表的过程,卡表和记忆集都是为了解决跨代引用的实现方案,后续讲GC时会有涉及_rem_set = collector_policy()->create_rem_set(_reserved, n_covered_regions);set_barrier_set(rem_set()->bs());_gch = this;for (i = 0; i < _n_gens; i++) {ReservedSpace this_rs = heap_rs.first_part(_gen_specs[i]->max_size(), false, false);_gens[i] = _gen_specs[i]->init(this_rs, i, rem_set());heap_rs = heap_rs.last_part(_gen_specs[i]->max_size());}clear_incremental_collection_failed();#if INCLUDE_ALL_GCS// If we are running CMS, create the collector responsible// for collecting the CMS generations.if (collector_policy()->is_concurrent_mark_sweep_policy()) {bool success = create_cms_collector();if (!success) return JNI_ENOMEM;}
#endif // INCLUDE_ALL_GCSreturn JNI_OK;
}
17.4.1.2 GenCollectedHeap::allocate
char* GenCollectedHeap::allocate(size_t alignment,size_t* _total_reserved,int* _n_covered_regions,ReservedSpace* heap_rs){const char overflow_msg[] = "The size of the object heap + VM data exceeds ""the maximum representable size";// Now figure out the total size.size_t total_reserved = 0;int n_covered_regions = 0;const size_t pageSize = UseLargePages ?os::large_page_size() : os::vm_page_size();assert(alignment % pageSize == 0, "Must be");// 遍历_gen_specs,求得新生代和老年代的分配大小for (int i = 0; i < _n_gens; i++) {total_reserved += _gen_specs[i]->max_size();if (total_reserved < _gen_specs[i]->max_size()) {vm_exit_during_initialization(overflow_msg);}n_covered_regions += _gen_specs[i]->n_covered_regions();  // 最终为2}assert(total_reserved % alignment == 0,err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment="SIZE_FORMAT, total_reserved, alignment));// Needed until the cardtable is fixed to have the right number// of covered regions.n_covered_regions += 2;  // 再加2,就是4,也就是把堆最终分成4个区(新生代、S1、S2、老年代)*_total_reserved = total_reserved;*_n_covered_regions = n_covered_regions;// 分配内存,实现细节看`章节17.4.2`*heap_rs = Universe::reserve_heap(total_reserved, alignment);return heap_rs->base();
}

17.4.2 universe.cpp

17.4.2.1 Universe::reserve_heap
ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) {assert(alignment <= Arguments::conservative_max_heap_alignment(),err_msg("actual alignment " SIZE_FORMAT " must be within maximum heap alignment " SIZE_FORMAT,alignment, Arguments::conservative_max_heap_alignment()));// 通过内存对齐,得到要分配的空间大小size_t total_reserved = align_size_up(heap_size, alignment);assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())),"heap size is too big for compressed oops");// 大页时考虑,本系列文章中不考虑大而情况,忽略bool use_large_pages = UseLargePages && is_size_aligned(alignment, os::large_page_size());assert(!UseLargePages|| UseParallelGC|| use_large_pages, "Wrong alignment to use large pages");// 取出Java堆的基址base的值,32位机器时,就是0,实现细节看`章节17.4.2.2`char* addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::UnscaledNarrowOop);// 创建一个ReservedHeapSpace对象,该对象就是用来保留连续内存地址范围空间的数据结构,实现细节看`章节17.4.3`ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr);if (UseCompressedOops) {if (addr != NULL && !total_rs.is_reserved()) {// Failed to reserve at specified address - the requested memory// region is taken already, for example, by 'java' launcher.// Try again to reserver heap higher.addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop);ReservedHeapSpace total_rs0(total_reserved, alignment,use_large_pages, addr);if (addr != NULL && !total_rs0.is_reserved()) {// Failed to reserve at specified address again - give up.addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::HeapBasedNarrowOop);assert(addr == NULL, "");ReservedHeapSpace total_rs1(total_reserved, alignment,use_large_pages, addr);total_rs = total_rs1;} else {total_rs = total_rs0;}}}if (!total_rs.is_reserved()) {vm_exit_during_initialization(err_msg("Could not reserve enough space for " SIZE_FORMAT "KB object heap", total_reserved/K));return total_rs;}if (UseCompressedOops) {// Universe::initialize_heap() will reset this to NULL if unscaled// or zero-based narrow oops are actually used.address base = (address)(total_rs.base() - os::vm_page_size());Universe::set_narrow_oop_base(base);}// 返回total_rsreturn total_rs;
}
17.4.2.2 Universe::preferred_heap_base
char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) {assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be");assert(is_size_aligned((size_t)UnscaledOopHeapMax, alignment), "Must be");assert(is_size_aligned(heap_size, alignment), "Must be");// HeapBaseMinAddress 是操作系统明确设定的堆内存的最低地址限制,默认设置的是2*G,这里按alignment对齐,把HeapBaseMinAddress的值按alignment对齐后,作为堆内存的最低地址uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment);size_t base = 0;
#ifdef _LP64  // 下面是对64位机器及使用压缩指针时的实现,我们只讲32位的,这块逻辑略过if (UseCompressedOops) {assert(mode == UnscaledNarrowOop  ||mode == ZeroBasedNarrowOop ||mode == HeapBasedNarrowOop, "mode is invalid");const size_t total_size = heap_size + heap_base_min_address_aligned;// Return specified base for the first request.if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) {base = heap_base_min_address_aligned;// If the total size is small enough to allow UnscaledNarrowOop then// just use UnscaledNarrowOop.} else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop)) {if ((total_size <= UnscaledOopHeapMax) && (mode == UnscaledNarrowOop) &&(Universe::narrow_oop_shift() == 0)) {// Use 32-bits oops without encoding and// place heap's top on the 4Gb boundarybase = (UnscaledOopHeapMax - heap_size);} else {// Can't reserve with NarrowOopShift == 0Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);if (mode == UnscaledNarrowOop ||mode == ZeroBasedNarrowOop && total_size <= UnscaledOopHeapMax) {// Use zero based compressed oops with encoding and// place heap's top on the 32Gb boundary in case// total_size > 4Gb or failed to reserve below 4Gb.uint64_t heap_top = OopEncodingHeapMax;// For small heaps, save some space for compressed class pointer// space so it can be decoded with no base.if (UseCompressedClassPointers && !UseSharedSpaces &&OopEncodingHeapMax <= 32*G) {uint64_t class_space = align_size_up(CompressedClassSpaceSize, alignment);assert(is_size_aligned((size_t)OopEncodingHeapMax-class_space,alignment), "difference must be aligned too");uint64_t new_top = OopEncodingHeapMax-class_space;if (total_size <= new_top) {heap_top = new_top;}}// Align base to the adjusted top of the heapbase = heap_top - heap_size;}}} else {// UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or// HeapBasedNarrowOop encoding was requested.  So, can't reserve below 32Gb.Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);}// Set narrow_oop_base and narrow_oop_use_implicit_null_checks// used in ReservedHeapSpace() constructors.// The final values will be set in initialize_heap() below.if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax)) {// Use zero based compressed oopsUniverse::set_narrow_oop_base(NULL);// Don't need guard page for implicit checks in indexed// addressing mode with zero based Compressed Oops.Universe::set_narrow_oop_use_implicit_null_checks(true);} else {// Set to a non-NULL value so the ReservedSpace ctor computes// the correct no-access prefix.// The final value will be set in initialize_heap() below.Universe::set_narrow_oop_base((address)UnscaledOopHeapMax);
#if defined(_WIN64) || defined(AIX)if (UseLargePages) {// Cannot allocate guard pages for implicit checks in indexed// addressing mode when large pages are specified on windows.Universe::set_narrow_oop_use_implicit_null_checks(false);}
#endif //  _WIN64}}
#endifassert(is_ptr_aligned((char*)base, alignment), "Must be");// 最终返回base,在32位机器时,虚拟机就是返回0return (char*)base; // also return NULL (don't care) for 32-bit VM
}

17.4.3 virtualspace.cpp

17.4.3.1 ReservedHeapSpace::ReservedHeapSpace
ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment,bool large, char* requested_address) :/* 先调用父类构造函数*/ReservedSpace(size, alignment, large,requested_address,(UseCompressedOops && (Universe::narrow_oop_base() != NULL) &&Universe::narrow_oop_use_implicit_null_checks()) ?lcm(os::vm_page_size(), alignment) : 0) {if (base() != NULL) {MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap);}// Only reserved space for the java heap should have a noaccess_prefix// if using compressed oops.protect_noaccess_prefix(size);
}
17.4.3.2 ReservedSpace::ReservedSpace
ReservedSpace::ReservedSpace(size_t size, size_t alignment,bool large,char* requested_address,const size_t noaccess_prefix) {initialize(size+noaccess_prefix, alignment, large, requested_address,noaccess_prefix, false);
}
17.4.3.3 ReservedSpace::initialize

入口函数: ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr);

参数:

total_reserved 对应 size:空间大小

alignment 对应 alignment:内存对齐值

use_large_pages 对应 large:这里不考虑大页,就设置为false

addr 对应 requested_address:32位时,addr为0

noaccess_prefix 为 0

executable 为 false

void ReservedSpace::initialize(size_t size, size_t alignment, bool large,char* requested_address,const size_t noaccess_prefix,bool executable) {// 看源码得知,这里就是取page size(页大小),没什么逻辑const size_t granularity = os::vm_allocation_granularity();// 断言检验assert((size & (granularity - 1)) == 0,"size not aligned to os::vm_allocation_granularity()");assert((alignment & (granularity - 1)) == 0,"alignment not aligned to os::vm_allocation_granularity()");assert(alignment == 0 || is_power_of_2((intptr_t)alignment),"not a power of 2");// 取二者最大值对齐alignment = MAX2(alignment, (size_t)os::vm_page_size());// Assert that if noaccess_prefix is used, it is the same as alignment.assert(noaccess_prefix == 0 ||noaccess_prefix == alignment, "noaccess prefix wrong");_base = NULL;_size = 0;_special = false;_executable = executable;_alignment = 0;_noaccess_prefix = 0;if (size == 0) {return;}// 不存在大页,special 为 falsebool special = large && !os::can_commit_large_page_memory();char* base = NULL;// 32位机器时 requested_address == 0,这条线也不会走if (requested_address != 0) {requested_address -= noaccess_prefix; // adjust requested addressassert(requested_address != NULL, "huge noaccess prefix?");}// special为false,这个if不会走if (special) {base = os::reserve_memory_special(size, alignment, requested_address, executable);if (base != NULL) {if (failed_to_reserve_as_requested(base, requested_address, size, true)) {// OS ignored requested address. Try different address.return;}// Check alignment constraints.assert((uintptr_t) base % alignment == 0,err_msg("Large pages returned a non-aligned address, base: "PTR_FORMAT " alignment: " PTR_FORMAT,base, (void*)(uintptr_t)alignment));_special = true;} else {// failed; try to reserve regular memory belowif (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||!FLAG_IS_DEFAULT(LargePageSizeInBytes))) {if (PrintCompressedOopsMode) {tty->cr();tty->print_cr("Reserve regular memory without large pages.");}}}}if (base == NULL) {if (requested_address != 0) {base = os::attempt_reserve_memory_at(size, requested_address);if (failed_to_reserve_as_requested(base, requested_address, size, false)) {// OS ignored requested address. Try different address.base = NULL;}} else {// 这一步就是通过系统调用mmap映射一块size大小的内存,Java堆内存就是mmap映射出来的base = os::reserve_memory(size, NULL, alignment);}// 映射失败,直接退出函数,分配Java堆内存失败if (base == NULL) return;// 验证对齐,为啥要验证呢,因为base是mmap映射后返回的内存首地址,这个地址是os自己的规则选取的一个地址,不一定能按照alignment对齐,所以这一定要验证if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) {// base没有对齐,只能释放刚才mmap映射的内存,然后重试if (!os::release_memory(base, size)) fatal("os::release_memory failed");// 确保对齐size = align_size_up(size, alignment);// 再次mmap映射内存,返回的base同样有上面一样的不对齐问题,所以这个函数中包含了手动对齐操作,细节看`章节17.4.3.4`base = os::reserve_memory_aligned(size, alignment);if (requested_address != 0 &&failed_to_reserve_as_requested(base, requested_address, size, false)) {// As a result of the alignment constraints, the allocated base differs// from the requested address. Return back to the caller who can// take remedial action (like try again without a requested address).assert(_base == NULL, "should be");return;}}}// Done_base = base;  // 最终拿到了Java堆的首地址_size = size;  // 最终拿到了Java堆的大小_alignment = alignment;  // 对齐值_noaccess_prefix = noaccess_prefix;  // 0// 断言判断assert(noaccess_prefix == 0 ||noaccess_prefix == _alignment, "noaccess prefix wrong");assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base,"area must be distinguisable from marks for mark-sweep");assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size],"area must be distinguisable from marks for mark-sweep");
}
17.4.3.4 os_posix.cpp->os::reserve_memory_aligned
char* os::reserve_memory_aligned(size_t size, size_t alignment) {assert((alignment & (os::vm_allocation_granularity() - 1)) == 0,"Alignment must be a multiple of allocation granularity (page size)");assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned");size_t extra_size = size + alignment;assert(extra_size >= size, "overflow, size is too large to allow alignment");// mmap映射一块内存区域,返回首地址char* extra_base = os::reserve_memory(extra_size, NULL, alignment);if (extra_base == NULL) {return NULL;}// 手动对齐char* aligned_base = (char*) align_size_up((uintptr_t) extra_base, alignment);// [  |                                       |  ]// ^ extra_base//    ^ extra_base + begin_offset == aligned_base//     extra_base + begin_offset + size       ^//                       extra_base + extra_size ^// |<>| == begin_offset//                              end_offset == |<>|// 用对齐后的地址-mmap的首地址,得出与首地址的偏移值size_t begin_offset = aligned_base - extra_base;// 结束地址对齐后的偏移size_t end_offset = (extra_base + extra_size) - (aligned_base + size);// begin_offset > 0,表示确实有偏移,那就把extra_base到偏移的这部分释放掉,因为有新的首地址了if (begin_offset > 0) {os::release_memory(extra_base, begin_offset);}// end_offset > 0,表示确实有偏移,那就把end_offset偏移的这部分释放掉,因为有新的限制地址了if (end_offset > 0) {os::release_memory(extra_base + begin_offset + size, end_offset);}// 返回首地址return aligned_base;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/612527.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

thinkphp学习07-数据库的数据查询

单数据查询 单条数据查询&#xff0c;一般是一维数组 Db::table()中 table 必须指定完整数据表&#xff08;包括前缀&#xff09;&#xff0c;如果配置了表前缀&#xff0c;Db::name()中可以忽略 如果希望只查询一条数据&#xff0c;可以使用 find()方法&#xff0c;需指定 wh…

Django 框架添加管理员,完成对普通用户信息管理

前情回顾&#xff1a;Django框架 完成用户登录注册 文章目录 1.创建管理员2.完善管理员功能2.1增加管理员登录功能2.2完善展示用户信息功能2.3完善修改用户信息功能2.4完善删除用户信息功能 1.创建管理员 一般管理员都是直接指定&#xff0c;不开放页面注册&#xff0c;可以直…

Mermaid 教程

Mermaid 教程 Mermaid 介绍 Mermaid 是一个用于生成流程图、时序图、甘特图等图表的 JavaScript 库。它使用类似于 Markdown 的文本语法&#xff0c;使得创建图表变得简单直观。以下是一个简单的 Mermaid 教程&#xff0c;介绍如何使用 Mermaid 创建流程图、时序图和甘特图。…

wxWidgets实战:使用mpWindow绘制阻抗曲线

选择模型时&#xff0c;需要查看model的谐振频率&#xff0c;因此需要根据s2p文件绘制一张阻抗曲线。 如下图所示&#xff1a; mpWindow 左侧使用mpWindow&#xff0c;右侧使用什么&#xff1f; wxFreeChart https://forums.wxwidgets.org/viewtopic.php?t44928 https://…

【MMC子系统】四、MMC控制器驱动层

我的圈子&#xff1a; 高级工程师聚集地 我是董哥&#xff0c;高级嵌入式软件开发工程师&#xff0c;从事嵌入式Linux驱动开发和系统开发&#xff0c;曾就职于世界500强企业&#xff01; 创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01; …

Keil编译生成的bin文件自动以版本号命名

Keil编译程序生成bin文件时&#xff0c;如何自动以版本号命名bin文件 一、目的二、方法三、实现过程1、脚本形式2、可执行文件形式 一、目的 Keil编译程序时&#xff0c;生成的Hex/Bin文件名字是根据Keil中工程配置里定的名字命名。通常代码里会有一个字段专门用来定义软件版本…

权限维持篇

一、Windows 1、 不死马权限维持 1.1 概述 <?php ignore_user_abort(); //关掉浏览器&#xff0c;PHP脚本也可以继续执行. set_time_limit(0);//通过set_time_limit(0)可以让程序无限制的执行下去 $interval 5; // 每隔*秒运行 do { $filename test.php; if(file_exi…

vue3.2引用unplugin-vue-components插入,解放开发中import组件

目录 前言引用unplugin-vue-components插件的优缺点优点缺点 unplugin-vue-components插件引入安装插件配置vite配置更新TypeScript配置使用代码位置 总结Q&A 前言 unplugin-vue-components是一个用于Vue.js项目的插件&#xff0c;特别适用于Vite和Webpack构建工具。它的主…

Java零基础教学文档第三篇:JDBC

今日新篇章 【JDBC】 【主要内容】 JDBC概述 使用JDBC完成添加操作 使用JDBC完成更新和删除 DBUtils的简单封装 使用JDBC完成查询 使用JDBC完成分页查询 常用接口详解 JDBC批处理 SQL注入问题 事务处理解决转账问题 连接池 使用反射对DBUtils再次的封装 BaseDAO的封…

Django报错处理

django.template.exceptions.TemplateDoesNotExist: django/forms/widgets/text.html django.template.exceptions.TemplateDoesNotExist: django/forms/widgets/number.html以上报错是pycharm中创建虚拟环境之后把原本自带的templates文件删除&#xff0c;重新在app01下面创建…

Unity Delaunay三角剖分算法 动态生成

Unity Delaunay三角剖分算法 动态生成 Delaunay三角剖分Delaunay三角剖分 定义Delaunay 边Delaunay 空圆特性 Delaunay 三角形Delaunay 最大化最小角特性 Delaunay 三角形特征Delaunay 算法Delaunay Lawson算法Delaunay Bowyer-Watson算法 Unity Delaunay三角剖分 应用Unity 工…

Linux——firewalld防火墙(二)

一、firewalld高级配置 1、IP地址伪装 地址伪装&#xff08;masquerade):通过地址伪装&#xff0c;NAT设备将经过设备的包转发到指定接收方&#xff0c;同时将通过的数据包的源地址更改为其自己的接口地址。当返回的数据包到达时&#xff0c;会将目的地址修改为原始主机的地址…

CMU15-445-Spring-2023-Project #2 - 前置知识(lec07-010)

Lecture #07_ Hash Tables Data Structures Hash Table 哈希表将键映射到值。它提供平均 O (1) 的操作复杂度&#xff08;最坏情况下为 O (n)&#xff09;和 O (n) 的存储复杂度。 由两部分组成&#xff1a; Hash Function和Hashing Scheme&#xff08;发生冲突后的处理&…

神经辐射场(NeRF)概述

神经辐射场&#xff08;NeRF&#xff09;是一种用于三维场景重建的深度学习算法。它能够从一组稀疏的二维图片中重建出高质量的三维场景。 以下是对NeRF算法的原理和实现方法的详细解释&#xff1a; NeRF算法原理&#xff1a; 基本概念&#xff1a; NeRF算法基于光线追踪的原理…

Unified-IO 2 模型: 通过视觉、语言、音频和动作扩展自回归多模态模型。给大家提前预演了GPT5?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

从0到1实现html文件转换为markdown文档(进度0.1)

Spider-Man 前言准备环境1、node.js2、git 执行指令顺序报错及其解决方案一、npm 错误&#xff01;可以在以下位置找到此运行的完整日志解决方案 二、没有修改权限解决方案&#xff1a; 注意事项总结 前言 当我们处理文档时&#xff0c;常常会遇到将HTML文档转换为Markdown文档…

残疾人聋哑人专用起床叫醒器震动起床提醒器

残疾人聋人专用起床叫醒器震动起床提醒器是为特殊教育学校提供的一种安全防护设施&#xff0c;符合特教行業標準8.7電教、信息網路設備的規定&#xff0c;系统采用了全自动IP网络控制、每个设备内带有IP地扯能独立控制每一个宿舍和教室&#xff0c;在同一时间内&#xff0c;多功…

TypeScript进阶(二)深入理解装饰器

✨ 专栏介绍 TypeScript是一种由微软开发的开源编程语言&#xff0c;它是JavaScript的超集&#xff0c;意味着任何有效的JavaScript代码都是有效的TypeScript代码。TypeScript通过添加静态类型和其他特性来增强JavaScript&#xff0c;使其更适合大型项目和团队开发。 在TypeS…

【解决】Unity Project 面板资源显示丢失的异常问题处理

开发平台&#xff1a;Unity 2021.3.7f1c1   一、问题描述 在开发过程中&#xff0c;遭遇 Project 面板资源显示丢失、不全的问题。但 Unity Console 并未发出错误提示。   二、解决方案&#xff1a;删除 Library 目录 前往 “工程目录/Library” 删除内部所有文件并重打开该…

【JVM】本地方法接口 Native Interface

一、JNI简介 JVM本地方法接口&#xff08;Java Native Interface&#xff0c;JNI&#xff09;是一种允许Java代码调用本地方法&#xff08;如C或C编写的方法&#xff09;的机制。这种技术通常用于实现高性能的计算密集型任务&#xff0c;或者与底层系统库进行交互。 二、JNI组…