Linux内核 内存管理 物理内存初始化流程
1.ARM64页表初始化流程图
start_kernel()│▼
setup_arch() // 架构相关初始化│▼
early_fixmap_init() // 初始化Fixmap(临时映射设备树等)│▼
arm64_memblock_init() // 从设备树解析内存布局│▼
arm64_memblock_reserve() // 保留内核镜像、initrd等区域│▼
paging_init() // 核心页表初始化函数├─▶ pgd_set_fixmap() // 获取swapper_pg_dir的物理地址├─▶ map_kernel() // 映射内核代码段(.text, .data等)│ ├─▶ __create_pgd_mapping()│ │ ├─▶ PGD → PUD → PMD → 填充大页表项(2MB/1GB)│ │ └─▶ 设置内存属性(如可缓存/设备内存)│├─▶ map_mem() // 线性映射所有物理内存│ ├─▶ for_each_mem_range()│ └─▶ __create_pgd_mapping() // 遍历所有内存区域并映射│├─▶ cpu_replace_ttbr1() // 切换TTBR1寄存器到新页表│ └─▶ load_ttbr1() // 加载swapper_pg_dir到TTBR1│└─▶ pgd_clear_fixmap() // 清理临时映射│▼
free_all_bootmem() // 将内存释放到伙伴系统
Fixmap初始化 (early_fixmap_init
)
建立临时映射,用于访问设备树(DTB)等关键数据。
内存探测 (arm64_memblock_init
)
从设备树解析物理内存布局(如memory@40000000
节点)。
保留关键区域 (arm64_memblock_reserve
)
保留内核镜像、initrd、设备树等区域不被分配。
页表初始化 (paging_init
)
映射内核代码段:将内核的代码段(_text
到_end
)映射到虚拟地址空间。
线性映射物理内存:将物理地址0x0
到最大物理地址映射到虚拟地址PAGE_OFFSET
(如0xffffff8000000000
)。
使用大页:默认使用2MB或1GB大页,减少页表层级。
切换页表寄存器 (cpu_replace_ttbr1
)
将新页表基地址(swapper_pg_dir
)写入TTBR1寄存器,完成页表切换。
释放内存到伙伴系统 (free_all_bootmem
)
将memblock中的内存转移到伙伴系统,完成内存管理初始化。
关键数据结构
物理内存管理:struct page, struct zone, struct pglist_data。
分配器:伙伴系统(free_area)、SLAB(kmem_cache)。
虚拟内存:vm_area_struct, mm_struct。
页表:pgd_t, pte_t等页表项。
高级功能:反向映射(anon_vma)、内存控制组(mem_cgroup)
2.ARM64架构内存初始化
文件路径: arch/arm64/mm/init.c
关键函数: bootmem_init()
→ paging_init()
代码逻辑:
// ARM64内存初始化流程
void __init bootmem_init(void) {// 1. 从设备树解析内存信息arm64_memblock_init();// 2. 保留内核镜像、initrd等区域arm64_memblock_reserve();// 3. 初始化页表并建立线性映射paging_init();// 4. 将内存释放到伙伴系统free_all_bootmem();}// 页表初始化
void __init paging_init(void) {// 创建swapper_pg_dir页表map_kernel(); // 映射内核代码段map_mem(); // 映射所有物理内存cpu_replace_ttbr1(lm_alias(swapper_pg_dir));}
1.从设备树解析内存布局 → 2. 保留关键区域 → 3. 初始化memblock → 4. 线性映射物理内存 → 5. 移交内存到伙伴系统。
1.从设备树解析内存信息
start_kernel()->setup_arch()->setup_machine_fdt()->early_init_dt_scan_nodes()->early_init_dt_scan_memory()
解析“memory”描述的信息从而得到内存的base_address和size信息,最后内存块信息通过early_init_dt_add_memory_arch ()->memblock_add()函数添加到memblock子系统中。
start_kernel()→ setup_arch(&command_line)→ setup_machine_fdt(__fdt_pointer) // 解析设备树→ early_init_dt_scan_nodes()→ early_init_dt_scan_memory() // 扫描设备树中的"memory"节点
2.物理内存映射
在内核使用内存前,需要初始化内核的页表,初始化页表主要在map_lowmem()函数中。在映射页表之前,需要把页表的页表项清零,主要在prepare_page_table()函数中实现。
void __init paging_init(void)
{phys_addr_t pgd_phys = early_pgtable_alloc(); // 分配PGD页表物理内存pgd_t *pgd = pgd_set_fixmap(pgd_phys); // 临时映射PGD页表到Fixmap区域map_kernel(pgd); // 映射内核镜像(代码、数据段等)map_mem(pgd); // 线性映射所有物理内存cpu_replace_ttbr1(lm_alias(pgd)); // 切换TTBR1到新页表init_mm.pgd = (pgd_t *)lm_alias(pgd); // 更新init_mm结构的PGD指针pgd_clear_fixmap(); // 清除PGD的临时Fixmap映射memblock_free(pgd_phys, PAGE_SIZE); // 释放临时PGD页表内存cpu_replace_ttbr1(NULL); // 确保TTBR1切换完成(屏障操作)
}
关键子函数与操作解析
1. early_pgtable_alloc()
作用:分配一个物理页用于存储顶级页表(PGD)。
实现细节:
调用memblock_alloc()从memblock分配器分配一个4KB页。
该页用于存储swapper_pg_dir(内核初始页表)。
2. pgd_set_fixmap(pgd_phys)
作用:将物理地址pgd_phys的PGD页表临时映射到内核Fixmap区域。
Fixmap区域:
一段预定义的虚拟地址空间,用于临时映射物理内存(如页表、设备树等)。
通过fixmap_remap_fdt()等函数使用。
3. map_kernel(pgd)
作用:映射内核镜像到虚拟地址空间,包括代码段(.text)、数据段(.data)、BSS段(.bss)等。
关键操作:
调用__create_pgd_mapping()创建页表项。
使用大页(如2MB或1GB)映射以减少页表层级。
映射范围:
内核的虚拟地址范围从_text到_end(通过链接脚本定义)。
4. map_mem(pgd)
作用:线性映射所有物理内存到内核虚拟地址空间。
实现细节:
遍历memblock.memory中的所有内存区域。
调用__create_pgd_mapping()为每个区域创建页表项。
物理地址phys → 虚拟地址__phys_to_virt(phys)(如0xffffff8000000000 + phys)。
特殊处理:
跳过标记为MEMBLOCK_NOMAP的内存区域(如设备树中的no-map属性区域)。
5. cpu_replace_ttbr1(pgd)
作用:将新的页表基地址(PGD)加载到TTBR1寄存器,完成页表切换。
关键操作:
调用load_ttbr1()函数写入TTBR1寄存器。
执行dsb(ishst)和isb()屏障指令确保操作完成。
ARM64地址空间划分:
TTBR0:用户空间页表基地址(低地址空间)。
TTBR1:内核空间页表基地址(高地址空间)。
6. pgd_clear_fixmap()
作用:清除PGD页表的Fixmap临时映射,释放Fixmap区域供后续使用。
页表映射的底层操作(__create_pgd_mapping)
map_kernel() 和 map_mem() 最终调用 __create_pgd_mapping() 创建页表项。其核心流程如下:
遍历页表层级:PGD → P4D → PUD → PMD → PTE。
分配页表页:若中间页表不存在,则分配物理页并填充。
设置页表项:
大页映射(如2MB或1GB)直接设置PMD或PUD项。
普通页映射(4KB)需要填充PTE项。
设置内存属性:
内核代码段:可执行、可读、不可写(MT_NORMAL)。
设备内存:不可缓存、不可执行(MT_DEVICE_nGnRnE)。
关键数据结构
pgd_t:顶级页表项(Page Global Directory)。
pud_t:页上级目录(Page Upper Directory)。
pmd_t:页中间目录(Page Middle Directory)。
pte_t:页表项(Page Table Entry)。
3.初始化页表paging_init
// arch/arm64/mm/mmu.c
void __init paging_init(void) {// 初始化swapper_pg_dirpgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));map_kernel(pgdp); // 映射内核代码/数据map_lowmem(); // 映射低端内存pgd_clear_fixmap();// ... 其他映射(如vmalloc、固定映射等)}
在 C 语言阶段(start_kernel → setup_arch → paging_init),内核构建完整的页表,取代临时页表。
关键步骤:
1.初始化 swapper_pg_dir:
正式内核页表基址,替代临时页表 init_pg_dir。
pgd_t *swapper_pg_dir = (pgd_t *)__pa_symbol(init_pg_dir); // 早期共享临时页表
2.映射内核代码和数据(map_kernel):
将内核镜像(_text 到 _end)映射到虚拟地址空间(可能包含 KASLR 偏移)。
__create_pgd_mapping(swapper_pg_dir, kernel_start, __phys_to_virt(kernel_start),
kernel_end - kernel_start, PAGE_KERNEL_ROX, NO_BLOCK_MAPPINGS);
3.线性映射低端内存(map_lowmem):
建立物理内存的线性直接映射(VA = PA + PAGE_OFFSET),覆盖所有可用内存区域。
for_each_memblock(memory, reg) {
__create_pgd_mapping(swapper_pg_dir, reg->base, __phys_to_virt(reg->base),
reg->size, PAGE_KERNEL, NO_CONT_MAPPINGS);
}
4.特殊区域映射:
vmalloc 区域:预留虚拟地址空间(VMALLOC_START 到 VMALLOC_END),动态分配时填充页表。
固定映射(Fixmap):用于临时映射设备寄存器(如 earlycon 串口)。
IO 映射:通过 ioremap 将设备内存映射到内核空间。
5.切换至正式页表:
更新 TTBR1_EL1 指向 swapper_pg_dir,刷新 TLB 和缓存
cpu_replace_ttbr1(lm_alias(swapper_pg_dir), init_mm.context.asid);
6.流程简要:
启动(物理地址模式)│├─ 汇编阶段(head.S)│ ├─ 配置控制寄存器(TCR_EL1, MAIR_EL1)│ ├─ 分配临时页表(init_pg_dir)│ └─ 创建恒等映射(内核镜像、页表自身、FDT)│├─ 启用 MMU(设置 SCTLR_EL1.M)│└─ C 语言阶段(paging_init)├─ 初始化 swapper_pg_dir├─ 映射内核代码(map_kernel)├─ 线性映射低端内存(map_lowmem)├─ 映射特殊区域(Fixmap、vmalloc)└─ 切换至正式页表(TTBR1_EL1)
5.zone的初始化
Zone初始化在内核启动过程中完成,主要分为以下阶段:
1.物理内存探测
设备树/ACPI解析:从设备树(DTB)或ACPI表中获取物理内存布局。
memblock初始化:通过memblock_add()和memblock_reserve()标记可用和保留的内存区域。
关键函数:
start_kernel()
→ setup_arch()
→ arm64_memblock_init() // 解析设备树,初始化memblock
2. 内存区域划分(Zone划分)
确定各Zone的物理地址范围:
ZONE_DMA:通常为物理地址0x0到某个上限(如4GB)。
ZONE_NORMAL:剩余物理内存。
关键函数:
bootmem_init()
→ zone_sizes_init() // 计算各Zone的起始页号和页数
ARM64实现:
// arch/arm64/mm/init.c
void __init zone_sizes_init(void) {unsigned long max_zone_pfn[MAX_NR_ZONES] = {0};// 遍历所有内存区域,确定各Zone的最大页号for_each_memblock(memory, reg) {phys_addr_t start = reg->base;phys_addr_t end = start + reg->size;unsigned long start_pfn = PFN_DOWN(start);unsigned long end_pfn = PFN_DOWN(end);if (start_pfn < max_dma_pfn)max_zone_pfn[ZONE_DMA] = max(max_zone_pfn[ZONE_DMA], end_pfn);elsemax_zone_pfn[ZONE_NORMAL] = max(max_zone_pfn[ZONE_NORMAL], end_pfn);}// 调用free_area_init()初始化Zonefree_area_init(max_zone_pfn);}
3. Zone数据结构初始化
关键函数:free_area_init_node()
为每个NUMA节点(Node)初始化其包含的Zone。
分配并初始化struct zone和struct pglist_data(Node描述符)。
流程:
分配pglist_data结构:描述一个NUMA节点的内存信息。
初始化Zone的free_area:伙伴系统的空闲链表。
计算水位线(Watermark):min, low, high,用于内存回收和分配策略。
初始化每CPU页面集(Per-CPU Pageset):加速单页分配。
代码路径:
free_area_init()
→ free_area_init_node(0, max_zone_pfn, ...) // 单NUMA节点
→ calculate_node_totalpages() // 计算Node的总页面数
→ free_area_init_core() // 初始化每个Zone
4. 伙伴系统(Buddy System)初始化
将memblock内存释放到伙伴系统:
调用memblock_free_all()将memblock管理的可用内存释放到伙伴系统的空闲链表中。
关键函数:
mem_init()
→ memblock_free_all() // 释放所有未被保留的内存到伙伴系统
→ free_low_memory_core_early()
→ __free_memory_core() // 按页释放到伙伴系统
5.关键数据结构
1. struct zone
描述一个内存区域的核心属性:
struct zone {
unsigned long watermark[NR_WMARK]; // 内存水位线(min, low, high)
struct free_area free_area[MAX_ORDER]; // 伙伴系统的空闲块链表
spinlock_t lock; // 并发锁
unsigned long managed_pages; // 被伙伴系统管理的页面数
const char *name; // Zone名称(如"DMA")
// 统计信息(活跃页、非活跃页等)
};
2. struct pglist_data(pg_data_t)
描述一个NUMA节点的内存布局:
typedef struct pglist_data {
struct zone node_zones[MAX_NR_ZONES]; // 节点包含的Zone
struct zonelist node_zonelists[MAX_ZONELISTS]; // 备用Zone列表(分配回退)
int nr_zones; // Zone数量
unsigned long node_start_pfn; // 节点的起始物理页号
unsigned long node_spanned_pages; // 节点总物理页数(含空洞)
unsigned long node_present_pages; // 实际可用物理页数(不含空洞)
// 其他统计信息和锁
} pg_data_t;
相关文章:
Linux内核 内存管理 物理内存初始化流程
1.ARM64页表初始化流程图 start_kernel()│▼ setup_arch() // 架构相关初始化│▼ early_fixmap_init() // 初始化Fixmap(临时映射设备树等)│▼ arm64_memblock_init() // 从设备树解析内存布局│▼ arm…...
Day23:和为s的数字
购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。 示例 1: 输入:price [3, 9, 12, 15], target 18 输出:[3,15] 或者 [15,3]示例 2&#x…...
Transformer 通关秘籍2:利用 BERT 将文本 token 化
前面两节分别通过两个代码示例展示了模型将文本转换为 token 之后是什么样的,希望你可以对此有一个感性的认识。 本节来简要介绍一下将一个连续的文本转换为 token 序列的大致过程,这个过程被称为分词,也叫 tokenization。 在你没了解这方面…...
电脑干货:万能驱动--EasyDrv8
目录 万能驱动EasyDrv8 功能介绍 主程序界面 驱动解压与安装 PE环境支持 系统部署环境 桌面环境一键解决方案 万能驱动8电脑版是由IT天空出品的一款智能识别电脑硬件并自动安装驱动的工具,一般又称为it天空万能驱动,万能驱动vip版,简称…...
18502 字符串哈希匹配字符串
18502 字符串哈希匹配字符串 ⭐️难度:中等 🌟考点:字符串hash 📖 📚 import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; import java.util.Scanner;public class Main {static int…...
openmmlab介绍 一下
OpenMMLab 是由商汤科技(SenseTime)发起并维护的开源深度学习项目,专注于计算机视觉领域。它提供了一系列模块化、可扩展的工具库,旨在帮助研究者和开发者高效地实现、复现和部署前沿的视觉算法。OpenMMLab 的设计强调模块化、…...
基于javaweb的SpringBoot线上网络文件管理系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…...
【设计模式】工厂模式详解-----简单工厂模式、工厂方法模式、抽象工厂模式
工厂模式详解 一、概述 工厂模式(Factory Pattern) 是一种 创建型设计模式,用于 封装对象的创建逻辑,避免在代码中直接实例化对象,从而提高代码的 可维护性、扩展性和解耦性。 二、工厂模式分类 工厂模式包括 简单工…...
【雅思播客09】Turn Left here.
Hello everyone! And welcome to my channel! Im Reevs. Good morning! 大家好,欢迎来到懒人英语晨读栏目,我是Reevs,早上好呀。 I have a great lesson for you today. 今天我有一堂非常棒的课。 We have an elementary lesson, which is …...
初阶7 vector
本章重点 vector的介绍vector的使用vector的模拟实现 1.vector的介绍 vector就类似数据结构中的顺序表 vector是表示可变大小数组的序列容器。 就像数组一样,vector也采用的连续存储空间来存储元素。 意味着可以采用下标对vector的元素 进行访问,和数…...
归并排序总结
归并排序是分治法的典型应用,把两个或k个有序的子序列合并为一个。2路归并,2合一。k路归并,k合一。内部排序通常采用2路归并排序,先将数组分成两半,分别排序,然后合并。合并的过程需要将两个有序的子数组合…...
ollama迁移已下载的单个模型到服务器
ollama迁移已下载的单个模型到服务器 场景 ollama是面向用户级的,部署和运行都很简单,是否高效就另说了。但最起码,他能充分利用用户的硬件设备,在GPU不足也能调用cpu和内存去加持。 ollama运行的模型基本是量化版本的…...
基于SSM+Vue物流信息管理系统(附源码)
预览页面 获取方式 https://gitee.com/XiaoLin_Java/communion/blob/master/README.en.md...
docker创建registry镜像仓库2.8版本
目录 shell脚本内容 运行效果 问题与解决 涉及镜像包registry:2.8(x86版本) shell脚本内容 [roottest1 docker]# cat registry.sh #!/bin/bash read -p "请输入用户:" user read -p "请输入密码:" passpathpwd passdir"$…...
Ubuntu下用QEMU模拟运行OpenBMC
1、前言 在调试过程中,安装了很多依赖库,具体没有记录。关于kvm,也没理清具体有什么作用。本文仅记录,用QEMU成功的将OpenBMC跑起来的过程,做备忘,也供大家参考。 2、环境信息 VMware Workstation 15 Pro…...
Unity Shader编程】之复杂光照
在Unity Shader的LightMode标签中,除了前向渲染和延迟渲染外,还支持多种渲染模式设置。以下是主要分类及用途: 一、核心渲染路径模式 前向渲染相关 ForwardBase 用于基础光照计算,处理环境光、主平行光、逐顶点/SH光源及光照贴图。…...
从零构建大语言模型全栈开发指南:第二部分:模型架构设计与实现-2.1.3前馈网络(FFN)与激活函数(GELU)优化
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 2.1.3 前馈网络(FFN)与激活函数(GELU)优化1. 前馈网络(FFN)的架构设计与数学原理1.1 FFN在Transformer中的核心作用2. GELU激活函数的数学特性与优化2.1 GELU的数学形式与近似计算3. 逐行代码实现…...
STM32 MODBUS-RTU主从站库移植
代码地址 STM32MODBUSRTU: stm32上的modbus工程 从站 FreeModbus是一个开源的Modbus通信协议栈实现。它允许开发者在各种平台上轻松地实现Modbus通信功能,包括串口和以太网。FreeMODBUS提供了用于从设备和主站通信的功能,支持Modbus RTU和Modbus TCP协…...
计算机是如何工作的
目录 冯诺依曼体系 CPU基本工作流程: 逻辑门 门电路 算术逻辑单元 ALU(Arithmetic&LogicUnit) 算术单元(Arithmetic Unit) 逻辑单元(Logic Unit) ALU符号 寄存器(Register)和内存(RAM) 控制单元 CU(Control Unit) 指令(Instruc…...
Arduino、ESP32驱动GUVA-S12SD UV紫外线传感器(光照传感器篇)
目录 1、传感器特性 2、控制器和传感器连线图 3、驱动程序 UV紫外线传感器是一个测试紫外线总量的最佳传感器,它不需要使用波长滤波器,只对紫外线敏感。 Arduino UV紫外线传感器,直接输出对应紫外线指数(UV INDEX)的线性电压,输出电压范围大约0~1100mV(对应UV INDEX值…...
【NLP 48、大语言模型的神秘力量 —— ICL:in context learning】
目录 一、ICL的优势 1.传统做法 2.ICL做法 二、ICL的发展 三、ICL成因的两种看法 1.meta learning 2.Bayesian Inference 四、ICL要点 ① 语言模型的规模 ② 提示词prompt中提供的examples数量和顺序 ③ 提示词prompt的形式(format) 五、fine-tune VS I…...
面向对象软件工程实践软件案例
智力运动-数字化思维训练课程介绍 数字化思维训练是科技赋能素质教育创新实践项目,通过数字化信息化手段,深度融合优质原创智力运动教育课程资源,服务幼儿园与小学,提供信息时代校园素质教育教学解决方案。在《面向对象软件工程》…...
PX4飞控-接收MAVLINK消息(2)-生成MAVLINK_MSG_ID_***.h文件
我在自制的底板上跑vxworks操作系统中移植了MAVLINK的C库用来与PX4飞控进行通信,其中使用的C库和其他依赖文件,例如common文件夹均为从飞控源码中获取,文件获取位置为px4-Autopolite/bulid/mavlink中,因为PX4源码中自带MAVLINK的依…...
Spring Boot 连接 MySQL 配置参数详解
Spring Boot 连接 MySQL 配置参数详解 前言参数及含义常用参数及讲解和示例useUnicode 参数说明: 完整配置示例注意事项 前言 在 Spring Boot 中使用 Druid 连接池配置 MySQL 数据库连接时,URL 中 ? 后面的参数用于指定连接的各种属性。以下是常见参数…...
【数据结构】_单链表_相关面试题(二)
本章重点 hello友友们~ 今天我们将对单链表的后半部分的相关面试题进行详细解析,下面就跟着我一起开启吧~ really GO! 1.相交链表 题目: 输入两个链表,找出它们的第一个公共结点。 代码分析: //找到相交结点…...
深入理解指针(2)(C语言版)
文章目录 前言一、数组名的理解二、使用指针访问数组三、一维数组传参的本质四、冒泡排序五、二级指针六、指针数组七、指针数组模拟二维数组总结 前言 在上一篇文章中,我们初步了解了指针的基本概念和用法。今天,我们将继续深入探索指针在数组、函数传…...
二叉树相关算法实现:判断子树与单值二叉树
目录 一、判断一棵树是否为另一棵树的子树 (一)核心思路 (二)代码实现 (三)注意要点 二、判断一棵树是否为单值二叉树 (一)核心思路 (二)代码实现…...
redux ,react-redux,redux-toolkit 简单总结
Redux、React-Redux 和 Redux Toolkit 是协同工作的三个库,各自承担不同角色,相互协同。 Redux:基础底座 底层状态管理库,负责状态存储、Action 派发和 Reducer 执行 React-Redux:连接 React 组件与 Redux Store 通…...
5. 实现一个中间件
原文地址: 实现一个中间件 更多内容请关注:php代码框架 理解中间件 中间件(Middleware) 是一种在请求被路由到控制器方法之前或响应返回客户端之前执行的代码。它通常用于处理通用任务,如身份验证、日志记录、CORS 处理等。 在…...
数据库理论基础
数据库理论基础 1.1 什么是数据库 数据: 描述事物的符号记录, 可以是数字、 文字、图形、图像、声音、语言等,数据有多种形式,它们都可以经过数字化后存入计算机。 数据库: 存储数据的仓库,是长期存放在…...
STM32学习笔记之振荡器(原理篇)
📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…...
SQL Server安装程序无法启动:系统兼容性检查失败
问题现象: 运行 SQL Server 2022 安装程序时,提示 “硬件或软件不满足最低要求”,安装向导直接退出或无法继续。 快速诊断 操作系统版本检查: # 查看 Windows 版本(需 20H2 或更高) winver 支持的系统&…...
C++20 中的std::c8rtomb和 std::mbrtoc8
文章目录 1. 引言2. std::c8rtomb 函数详解3. std::mbrtoc8 函数详解4. 使用示例5. 注意事项6. 总结 1. 引言 C20 标准引入了对 UTF-8 编码的更好支持,其中包括两个重要的函数:std::c8rtomb 和 std::mbrtoc8。这两个函数分别用于将 UTF-8 编码的字符转换…...
树形结构的工具类TreeUtil
这个地方是以null为根节点,相关以null或者0自己在TreeUtil中加代码,就行 基础类 package com.jm.common.entity;import lombok.Data;import java.util.ArrayList; import java.util.List;/*** Author:JianWu* Date: 2025/3/26 9:02*/ Data public clas…...
【零基础入门unity游戏开发——2D篇】2D物理系统 —— 2D刚体组件(Rigidbody2D)
考虑到每个人基础可能不一样,且并不是所有人都有同时做2D、3D开发的需求,所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】:主要讲解C#的基础语法,包括变量、数据类型、运算符、流程控制、面向对象等,适合没有编程基础的…...
人员进出新视界:视觉分析算法的力量
视觉分析赋能离岗检测新策略 随着时代的发展,失业率增加,社会安保压力也随之增大。企业为了提升管理效率,保障园区安全,对员工离岗检测的需求日益迫切。传统的离岗管理方式,如人工巡逻、打卡记录等,不仅效率…...
LabVIEW液压振动锤控制系统
在现代工程机械领域,液压振动锤的高效与精准控制日益显得重要。本文通过LabVIEW软件,展开液压振动锤启停共振控制技术的研究与应用,探讨如何通过改进控制系统来优化液压振动锤的工作性能,确保其在复杂工况下的稳定性与效率。 …...
Slidev使用(一)安装
文章目录 1. **安装位置**2. **使用方式**3. **适用场景**4. **管理和维护** 全局安装1. **检查 Node.js 和 npm 是否已安装**2. **全局安装 Slidev CLI**3. **验证安装是否成功**4. **创建幻灯片文件**5. **启动 Slidev**6. **实时编辑和预览**7. **构建和导出(可选…...
浙大:DeepSeek技术溯源及前沿探索
浙江大学DS系列专题《DeepSeek技术溯源及前沿探索》由朱强教授主讲,内容主要包括 语言模型、Transformer、ChatGPT、DeepSeek及新一代智能体 等核心主题。 下载方式:关注“渡江客涂鸦板”,回复ds1253免费获取下载地址 语言模型:语…...
【八股】未知宽高元素水平垂直居中的三种方法
在笔试/面试中,经常出现的一个问题就是:如何实现元素水平垂直居中? 本文会直接使用代码,介绍未知宽高元素水平垂直居中的三种方法: 方法一:绝对定位absolute //绝对定位,将元素的左右位置设置…...
23种设计模式-中介者(Mediator)设计模式
中介者设计模式 🚩什么是中介者设计模式?🚩中介者设计模式的特点🚩中介者设计模式的结构🚩中介者设计模式的优缺点🚩中介者设计模式的Java实现🚩代码总结🚩总结 🚩什么是…...
(免费开源)图片去水印以及照片擦除功能,你会选择使用吗?
图片去水印以及相关人物擦除是一个非常小众的需求,就是将原本图片上的文字或者logo去除让变成一个干净的图片,但市面上很多都是付费的,今天就介绍一下这款免费工具。 工具演示效果 工具介绍 名称:lama-projct 利用AI模型训练LaM…...
Rust 学习笔记(一)
本文是博主学Rust的学习笔记,将学习经历整理下来,学习接收的内容更加条理且以便回顾。 参照学习资料为Rust官方文档,如内容中有误还请指点(一般没有☺) 一. 项目搭建 1.创建项目 cargo new hello_cargo cd hello_c…...
C++vector常用接口和模拟实现
C中的vector是一个可变容量的数组容器,它可以像数组一样使用[]进行数据的访问,但是又不像C语言数组空间是静态的,它的空间是动态可变的。 在日常中我们只需要了解常用的接口即可,不常用的接口查文档即可。 1.构造函数 //空构造…...
AI数据分析:一键生成数据分析报告
作为一名数据分析师,我们经常需要做一些数据分析报告,今天我就来手把手教你如何使用大模型一键生成高质量的数据分析报告,提高你的工作效率。 假设你是一家新零售企业的销售分析师,有一份销售数据,数据结构如数据结构…...
leetcode 2829. k-avoiding 数组的最小总和 中等
给你两个整数 n 和 k 。 对于一个由 不同 正整数组成的数组,如果其中不存在任何求和等于 k 的不同元素对,则称其为 k-avoiding 数组。 返回长度为 n 的 k-avoiding 数组的可能的最小总和。 示例 1: 输入:n 5, k 4 输出&…...
微信小程序登录和获取手机号
目录 准备工作 实现流程 实现代码 公共部分 通过code获取openid等信息 解密手机号 扩展 不借助工具类实现解密 借助工具类获取access_token 准备工作 需要小程序账号(可以去微信公众平台创建一个测试号或者正式号) appid:小程序id …...
漫画|基于SprinBoot+vue的漫画网站(源码+数据库+文档)
漫画网站 目录 基于SprinBootvue的漫画网站 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大…...
华鲲振宇天工TG225 B1国产服务器试装openEuler22.03 -SP4系统
今天测试了一下在华鲲振宇公司的天工TG225 B1国产服务器上进行openEuler22.03 -SP4操作系统的试装,本文记录整个测试过程。 一、服务器信息 1、服务器型号 Huakun TG225 B1 (D) 2、登录IPMI帐户信息 初始用户名Tech.ON 密码TianGong8000 二、磁盘RAID配置 测试…...
Graphpad Prism for Mac医学绘图
Graphpad Prism for Mac医学绘图 文章目录 Graphpad Prism for Mac医学绘图一、介绍二、效果三、下载 一、介绍 GraphPad Prism for Mac是一款功能强大、易于使用的科学和统计分析软件,适用于各种类型的数据处理和可视化需求。无论您是进行基础研究、临床试验还是学…...