UEFI——获取UEFI MemoryMap

news/2024/9/16 22:38:21/ 标签: UEFI, bios

一、MemoryMap简介

首先讲一下什么是MemoryMap?

内存映射(Memory Mapping)是一种将文件内容映射到进程的虚拟地址空间的技术。在这种机制下,文件可以视为内存的一部分,从而允许程序直接对这部分内存进行读写操作,而无需传统的I/O调用。内存映射缓冲区利用虚拟内存机制,让操作系统将一部分磁盘文件映射到进程地址空间的一块连续区域当中。操作系统负责管理内存页的加载和卸载,应用程序只需要访问这块内存区域即可,从而避免了频繁的磁盘I/O操作和多余的系统调用。

UEFI的内存映射

  • UEFI内存映射是由UEFI固件提供的,主要用于在启动过程中描述系统的内存布局。它告诉操作系统和启动软件哪些内存区域是可用的,哪些是保留的。
  • 实现UEFI内存映射通常是在系统启动的早期阶段由UEFI固件创建的,它包括了系统内存的详细信息,如内存大小、类型和状态。

UEFI MemoryMap指的是UEFI运行时环境中的一个数据结构,它包含了当前系统内存的详细信息.MemoryMap记录了系统内存的布局,包括所有可用的区域、内存类型、属性以及使用情况。

内存类型:MemoryMap中的每个内存区域都有一个与之关联的类型

        在UEFI中引入的内存类型由以下几种:

typedef enum {EfiReservedMemoryType, //没有用到的EfiLoaderCode, //已加载的UEFI应用程序的代码部分EfiLoaderData, //已加载的UEFI应用程序的数据部分和默认数据分配EfiBootServicesCode, //已加载的 Boot Services 驱动程序的代码部分EfiBootServicesData, //已加载的 Boot Services 驱动程序的数据部分EfiRuntimeServicesCode, //已加载的Runtime Services驱动的代码部分EfiRuntimeServicesData, //已加载的Runtime Services驱动的数据部分EfiConventionalMemory, //空闲(未分配)内存EfiUnusableMemory, //检测到错误的内存EfiACPIReclaimMemory, //保存ACPI表的内存EfiACPIMemoryNVS, //为固件保留的地址空间EfiMemoryMappedIO, //系统固件使用它来请求操作系统将内存映射的 IO 区域映射到虚拟地址,以便 EFI 运行时服务可以访问它。EfiMemoryMappedIOPortSpace, //系统内存映射的 IO 区域,处理器用它来将内存周期转换为 IO 周期。EfiPalCode, //固件为作为处理器一部分的代码保留的地址空间。EfiPersistentMemory, //一个内存区域,它作为 EfiConventionalMemory 运行,但它也恰好支持字节寻址的非易失性。EfiUnacceptedMemoryType, //描述未被接受的系统内存的内存区域。EfiMaxMemoryType,//// +---------------------------------------------------+// | 0..(EfiMaxMemoryType - 1)    - Normal memory type |// +---------------------------------------------------+// | EfiMaxMemoryType..0x6FFFFFFF - Invalid            |// +---------------------------------------------------+// | 0x70000000..0x7FFFFFFF       - OEM reserved       |// +---------------------------------------------------+// | 0x80000000..0xFFFFFFFF       - OS reserved        |// +---------------------------------------------------+//MEMORY_TYPE_OEM_RESERVED_MIN = 0x70000000,MEMORY_TYPE_OEM_RESERVED_MAX = 0x7FFFFFFF,MEMORY_TYPE_OS_RESERVED_MIN  = 0x80000000,MEMORY_TYPE_OS_RESERVED_MAX  = 0xFFFFFFFF
} EFI_MEMORY_TYPE;

内存属性:写保护、都保护、执行保护、非易失性、只读、运行时等等等等

内存区域:

使用情况:

UEFI MemoryMap的主要用途包括:

操作系统加载器:操作系统加载器在启动过程中会使用MemoryMap来确定哪些内存是可用的,以及如何配置和使用这些内存。

UEFI应用程序:UEFI应用程序可以使用MemoryMap来了解内存布局,以便它们可以请求和分配内存。

内存管理:UEFI固件使用MemoryMap来管理内存分配,确保不同组件之间不会发生内存冲突。

UEFI规范中用结构体EFI_MEMORY_DESCRIPTOR来描述内存区域,在UEFI环境中,EFI_MEMORY_DESCRIPTOR被用来标识内存映射(Memory Map)中的一个条目,即内存映射的每一项都是一个EFI_MEMORY_DESCRIPTOR结构。UEFI应用程序和驱动程序可以使用EFI_BOOT_SERVICES.GetMemoryMap服务来获取当前的内存映射,这个映射是一个EFI_MEMORY_DESCRIPTOR数组。通过便利这个数组,应用程序可以了解系统的内存布局,并据此进行内存管理操作。

EFI_MEMORY_DESCRIPTOR的代码原型为:

typedef struct {UINT32                Type;                   // 描述内存的类型EFI_PHYSICAL_ADDRESS  PhysicalStart;          // 内存区域的物理起始地址EFI_VIRTUAL_ADDRESS   VirtualStart;           // 内存区域的虚拟起始地址(如果适用)UINT64                NumberOfPages;          // 内存区域包含的页数UINT64                Attribute;              // 内存区域的属性
} EFI_MEMORY_DESCRIPTOR;

二、获取UEFI MemoryMap

UEFI的内存服务提供了EFI_GET_MEMORY_MAP.GetMemoryMap接口来获取当前的内存映射,其代码原型为:

//返回当前的Memory Map@retval EFI_SUCCESS           The memory map was returned in the MemoryMap buffer.内存映射已经返回到Memmorymap缓冲区@retval EFI_BUFFER_TOO_SMALL  The MemoryMap buffer was too small. The current buffer sizeneeded to hold the memory map is returned in MemoryMapSize.表示MemmoryMap缓冲区太小了,目前需要用来保存内存映射的缓冲区大小已经返回到MemmoryMapSize中。@retval EFI_INVALID_PARAMETER 1) MemoryMapSize is NULL.2) The MemoryMap buffer is not too small and MemoryMap isNULL.表示MemorymapSize为空,或memmoryMap缓冲区并不小,但是MemMorymap是空的typedef
EFI_STATUS
(EFIAPI *EFI_GET_MEMORY_MAP)(IN OUT UINTN                       *MemoryMapSize, //输入,输出参数,指向memorymap缓冲区大小的指针,单位为字节。在输入时,这是调用者分配的缓冲区大小。在输出时,如果缓冲区足够大,这是固件返回的缓冲区大小;如果缓冲区过小,则是包含映射所需要的缓冲区大小。OUT    EFI_MEMORY_DESCRIPTOR       *MemoryMap, //输出参数,指向固件存放当前内存映射的缓冲区的指针OUT    UINTN                       *MapKey, //输出参数,指向固件返回当前内存映射键的位置的指针OUT    UINTN                       *DescriptorSize, //输出参数,指向固件返回单个EFI_MEMORY_DESCRIPTOR的大小(以字节为单位)的位置的指针。OUT    UINT32                      *DescriptorVersion //指向固件返回与 EFI_MEMORY_DESCRIPTOR 关联的版本号的位置的指针。);

如果GetMemoryMap的返回值为EFI_BUFFER_TOO_SMALL,说明MemoryMap缓冲区太小,已经将用来保存内存映射的缓冲区大小返回到MemoryMapSize中了。接下来就需要使用AllocatePool重新分配缓冲区。其代码原型为

/**Allocates a buffer of type EfiBootServicesData.按照字节数分配EfiBootServicesData类型的内存,并返回一个指向所分配缓冲区的指针
**/
VOID *
EFIAPI
AllocatePool (IN UINTN  AllocationSize //需要分配的字节数);

完整代码如下:

#include <uefi.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>EFI_STATUS
EFIAPI
MyMemMapEntry(IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable
)
{EFI_STATUS                Status;UINTN                     EfiMemoryMapSize;EFI_MEMORY_DESCRIPTOR     *EfiMemoryMap;EFI_MEMORY_DESCRIPTOR     *EfiMemoryMapEnd;EFI_MEMORY_DESCRIPTOR     *EfiEntry;UINTN                     EfiMapKey;UINTN                     EfiDescriptorSize;UINT32                    EfiDescriptorVersion;UINT64                    BootServicesDataPage = 0;UINT64                    BootServicesCodePage = 0;UINT64                    ACPIReclaimMemoryPage = 0;UINT64                    ACPIMemoryNVSPage = 0;UINT64                    ReservedMemoryTypePage = 0;UINT64                    RuntimeServicesCodePage = 0;UINT64                    RuntimeServicesDataPage = 0;UINT64                    LoaderCodePage = 0;UINT64                    LoaderDataPage = 0;UINT64                    MaxMemoryTypePage = 0;UINT64                    ConventionalMemoryPage = 0;UINT64                    UnusableMemoryPage = 0;UINT64                    MemoryMappedIOPage = 0;UINT64                    MemoryMappedIOPortSpacePage = 0;UINT64                    PalCodePage = 0;UINT64                    PersistentMemoryPage = 0;EfiMemoryMapSize = 0;EfiMemoryMap = NULL;Status = gBS->GetMemoryMap ( //获取MemoryMap&EfiMemoryMapSize,EfiMemoryMap,&EfiMapKey,&EfiDescriptorSize,&EfiDescriptorVersion);ASSERT (Status == EFI_BUFFER_TOO_SMALL); //过小重新分配do {EfiMemoryMap = AllocatePool (EfiMemoryMapSize);if (EfiMemoryMap == NULL){DEBUG ((EFI_D_ERROR, "ERROR!! Null Pointer returned by AllocatePool ()\n"));ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);return Status;}Status = gBS->GetMemoryMap (&EfiMemoryMapSize,EfiMemoryMap,&EfiMapKey,&EfiDescriptorSize,&EfiDescriptorVersion);if (EFI_ERROR(Status)) {FreePool (EfiMemoryMap); //释放掉前面分配的}} while (Status == EFI_BUFFER_TOO_SMALL); //一直小一直分配,直到不再小DEBUG((DEBUG_ERROR | DEBUG_PAGE,"[CSDN] EfiMemoryMapSize=0x%x EfiDescriptorSize=0x%x EfiMemoryMap=0x%x \n", EfiMemoryMapSize, EfiDescriptorSize, (UINTN)EfiMemoryMap));EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)EfiMemoryMap + EfiMemoryMapSize); //映射区结尾EfiEntry = EfiMemoryMap; //映射区的开始地址DEBUG((DEBUG_ERROR | DEBUG_PAGE,"===========================%S============================== Start\n", L"CSDN MemMap"));while (EfiEntry < EfiMemoryMapEnd) { //循环获取各内存类型的信息if (EfiEntry->Type == EfiReservedMemoryType){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiReservedMemoryType  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));ReservedMemoryTypePage = ReservedMemoryTypePage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiLoaderCode){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiLoaderCode  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));LoaderCodePage = LoaderCodePage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiLoaderData){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiLoaderData  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));LoaderDataPage = LoaderDataPage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiBootServicesCode){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiBootServicesCode  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));BootServicesCodePage = BootServicesCodePage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiBootServicesData){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiBootServicesData  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));BootServicesDataPage = BootServicesDataPage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiRuntimeServicesCode){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiRuntimeServicesCode  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));RuntimeServicesCodePage = RuntimeServicesCodePage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiRuntimeServicesData){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiRuntimeServicesData  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));RuntimeServicesDataPage = RuntimeServicesDataPage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiConventionalMemory){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiConventionalMemory  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));ConventionalMemoryPage = ConventionalMemoryPage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiUnusableMemory){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiUnusableMemory  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));UnusableMemoryPage = UnusableMemoryPage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiACPIReclaimMemory){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiACPIReclaimMemory  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));ACPIReclaimMemoryPage = ACPIReclaimMemoryPage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiACPIMemoryNVS){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiACPIMemoryNVS  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));ACPIMemoryNVSPage = ACPIMemoryNVSPage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiMemoryMappedIO){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiMemoryMappedIO  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));MemoryMappedIOPage = MemoryMappedIOPage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiMemoryMappedIOPortSpace){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiMemoryMappedIOPortSpace  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));MemoryMappedIOPortSpacePage = MemoryMappedIOPortSpacePage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiPalCode){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiPalCode  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));PalCodePage = PalCodePage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiPersistentMemory){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiPersistentMemory  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));PersistentMemoryPage = PersistentMemoryPage + EfiEntry->NumberOfPages;}else if (EfiEntry->Type == EfiMaxMemoryType){DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiMaxMemoryType  %3d %16lx pn %16lx \n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->NumberOfPages));MaxMemoryTypePage = MaxMemoryTypePage + EfiEntry->NumberOfPages;}EfiEntry = NEXT_MEMORY_DESCRIPTOR(EfiEntry, EfiDescriptorSize);}DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiBootServicesData Page Number: %16lx  %dMB\n", BootServicesDataPage, BootServicesDataPage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiBootServicesCode Page Number: %16lx  %dMB\n", BootServicesCodePage, BootServicesCodePage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiACPIReclaimMemory Page Number: %16lx  %dMB\n", ACPIReclaimMemoryPage, ACPIReclaimMemoryPage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiACPIMemoryNVS Page Number: %16lx  %dMB\n", ACPIMemoryNVSPage, ACPIMemoryNVSPage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiReservedMemoryType Page Number: %16lx  %dMB\n", ReservedMemoryTypePage, ReservedMemoryTypePage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiRuntimeServicesCode Page Number: %16lx  %dMB\n", RuntimeServicesCodePage, RuntimeServicesCodePage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiRuntimeServicesData Page Number: %16lx  %dMB\n", RuntimeServicesDataPage, RuntimeServicesDataPage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiLoaderCode Page Number: %16lx  %dMB\n", LoaderCodePage, LoaderCodePage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiLoaderData Page Number: %16lx  %dMB\n", LoaderDataPage, LoaderDataPage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiMaxMemoryType Page Number: %16lx  %dMB\n", MaxMemoryTypePage, MaxMemoryTypePage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiConventionalMemory Page Number: %16lx  %dMB\n", ConventionalMemoryPage, ConventionalMemoryPage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiUnusableMemory Page Number: %16lx  %dMB\n", UnusableMemoryPage, UnusableMemoryPage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiMemoryMappedIO Page Number: %16lx  %dMB\n", MemoryMappedIOPage, MemoryMappedIOPage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiMemoryMappedIOPortSpace Page Number: %16lx  %dMB\n", MemoryMappedIOPortSpacePage, MemoryMappedIOPortSpacePage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiPalCode Page Number: %16lx  %dMB\n", PalCodePage, PalCodePage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE, "[CSDN] EfiPersistentMemory Page Number: %16lx  %dMB\n", PersistentMemoryPage, PersistentMemoryPage*4/1024));DEBUG((DEBUG_ERROR | DEBUG_PAGE,"===========================%S============================== End\n", L"CSDN MemMap"));return Status;
}

编写inf代码,编译,运行efi文件 

部分运行结果如下:

显示内存类型                                                物理地址                         页数

这是一个memmap dump demo,使用该demo可以得出当前BIOS的mem region分配情况,在shell下同样可以使用内置的memmap 命令来查看当前memory map。 


http://www.ppmy.cn/news/1523340.html

相关文章

AIGC 初识 GAN(Generative Adversarial Networks,生成对抗网络)是如何工作的,浅记。

GAN&#xff08;Generative Adversarial Networks&#xff0c;生成对抗网络&#xff09;是一种深度学习模型&#xff0c;它通过生成器和判别器之间的对抗训练来生成逼真的数据样本。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 GAN&#xff08;Gene…

FPGA第 9 篇,Verilog 中的关键字和基数

前言 在 Verilog 中&#xff0c;关键字&#xff08;Keywords&#xff09;和基数&#xff08;Radix&#xff09;是语言的重要组成部分&#xff0c;它们有助于描述和定义硬件设计。上期分享了 Verilog 的基本使用&#xff0c;以及数据类型、逻辑值和算数运算符的简单应用&#x…

Obsidian git sync error / Obsidian git 同步失敗

Issue: commit due to empty commit message Solution 添加commit資訊&#xff0c;確保不留空白 我的設置&#xff1a;auto-backup: {{hostname}}/{{date}}/

AWS EC2安全组配置:轻松开放端口访问

在AWS EC2实例上开放特定端口是配置服务器安全性和可访问性的重要步骤。本文中九河云将介绍如何通过AWS控制台配置EC2安全组来实现端口开放。 1. 登录AWS控制台 首先,登录到AWS管理控制台,并导航到EC2服务页面。 2. 找到目标EC2实例 在EC2控制面板中,找到需要开放端口的实例…

投放Facebook广告开户全流程解析:从开户到广告投放的实用指南

Facebook作为全球最大的社交平台之一&#xff0c;广告业务覆盖范围广泛&#xff0c;已成为各类企业推广产品和服务的重要渠道。要在Facebook上成功投放广告&#xff0c;首先需要完成广告账户的开户流程。本文将详细介绍投放Facebook广告开户的步骤和条件&#xff0c;并解释如何…

随身 WiFi 大探秘:芯片竟有二手货?快来避雷!随身wifi芯片哪个好?随身wifi芯片排行榜!

你的随身wifi芯片可能是二手的...是的&#xff0c;你没听错&#xff01; 随身wifi的好坏主要取决于芯片&#xff0c;他决定了网速&#xff0c;散热性等关键性能。目前市场上常见的随身 WiFi 芯片有多种&#xff0c;我们该如何挑选高性能芯片&#xff0c;避免买到二手芯片设备呢…

python之异步任务

在 Python 中&#xff0c;异步任务通常通过使用库如 Celery 来实现。Celery 是一个简单、灵活且可靠的分布式系统&#xff0c;用于处理大量消息&#xff0c;同时提供操作控制。 在 Celery 中&#xff0c;delay 和 apply_async 是两种常用的方法来调度异步任务。 delay 方法 …

Harmony arkTs组件开发:ListItem控件中不能使用多个组件

如下代码&#xff1a; List(){ForEach(this.indexList, (item: number) >{ListItem(){Text("测试")Row(){Image(this.images[item]).width(20).height(20).margin({left:15})Text(this.arr[item])//.width(80%).fontSize(sizes.oneFontSize).fontColor(colors.Tit…

Web 原生组件化方案:Web Components

你好&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注。 Web 组件化是一种将Web应用的UI部分拆分成可复用的独立组件的架构方法。这种方法有助于提高代码的可维护性、可重用性和可测试性。 而Web Components 标准则提供了一套原生的API&#xff0c;允许开发者创建…

【阿雄不会写代码】全国职业院校技能大赛GZ036第十套

也不说那么多了&#xff0c;要用到这篇博客&#xff0c;肯定也知道他是干嘛的&#xff0c;给博主点点关注点点赞&#xff01;&#xff01;&#xff01;这样博主才能更新更多免费的教程&#xff0c;不然就直接丢付费专栏里了&#xff0c;需要相关文件请私聊

Java进阶13讲__第12讲_2/2

线程安全问题 线程同步方案 线程池 线程通信 理论补充 1. 线程安全问题 1.1 举例说明 1.2 代码实现 package com.itheima.a_线程安全;/* 线程安全:多个线程同时修改同一个资源取钱案例小明和小红是一对夫妻&#xff0c;他们有一个共同的账户&#xff0c;余额是10万元如…

《React Native 应用开发最佳实践》

⭐️React Native 应用开发最佳实践⭐️ 近年来&#xff0c;React Native 应用开发因其能够使用 JavaScript 构建原生移动应用的能力而大受欢迎。它提供了跨平台兼容性、更快的开发时间以及更易于维护的特性&#xff0c;成为了许多开发者的首选。然而&#xff0c;要确保 React…

免费的 Mac 应用清理工具Pearcleaner v3.8.6

免费的 Mac 应用清理工具。这是一款免费开源的 Mac 应用清理工具&#xff0c;能够彻底卸载应用并清理残留文件。它采用 SwiftUI 开发&#xff0c;提供了简单易用的界面&#xff0c;支持右键卸载、迷你模式和 Homebrew 清理等功能。 下载链接&#xff1a;https://pan.quark.cn/s…

计算机网络(三) —— 简单Udp网络程序

目录 一&#xff0c;初始化服务器 1.0 辅助文件 1.1 socket函数 1.2 填充sockaddr结构体 1.3 bind绑定函数 1.4 字符串IP和整数IP的转换 二&#xff0c;运行服务器 2.1 接收 2.2 处理 2.3 返回 三&#xff0c;客户端实现 3.1 UdpClient.cc 实现 3.2 Main.cc 实现 …

前端面试热点题目——typescript篇

在TypeScript面试中&#xff0c;面试官通常会考察你对TypeScript特性的理解、类型系统的掌握、以及在实际项目中的应用能力。以下是一些热点题目及其相应的代码示例&#xff0c;旨在帮助你准备TypeScript相关的面试。 1. 类型别名与接口的区别及使用场景 问题&#xff1a;请解…

react js 笔记 3

起因&#xff0c; 目的: 专注。 学习 react js 的时候&#xff0c; 就专注这一方面 &#xff0c;其他都不要碰。 比如&#xff0c; python, C语言&#xff0c; R, 都不看。 只看 js.专注&#xff0c;减少来回切换。 重复。 自己写的笔记&#xff0c;需要反复多看几遍&#xff…

java开发后端

1.BeanUtils.toBean 方法 它是一个常见的 Java 工具方法&#xff0c;用于将一个 JavaBean 对象转换为另一个 JavaBean 对象 FlowOrderDO flowOrder BeanUtils.toBean(createReqVO, FlowOrderDO.class); 这行代码使用了 BeanUtils.toBean 方法&#xff0c;它是一个常见的 Ja…

MySQL笔记2(DQL查询语言【条件、分组、排序、限制、子查询、左右连接、内连接、联合查询】)

DQL数据查询语言与项目高级查询实战 先安装数据库并创建一个库 并创建以下数据 /*创建部门表*/CREATE TABLE dept( deptnu INT PRIMARY KEY comment 部门编号, dname VARCHAR(50) comment 部门名称, addr VARCHAR(50) comment 部门地址 );/*某个公司的员工表*/ CREATE TABLE…

html备忘录

备忘录 网站收藏数据&#xff1a; 网站收藏.js const webLinks [{ title: "智能翻译", src: "https://fanyi.baidu.com" },{ title: "哔哩哔哩", src: "https://www.bilibili.com" },{ title: "百度一下&#xff0c;你就知道&…

漫谈设计模式 [9]:外观模式

引导性开场 菜鸟&#xff1a;老鸟&#xff0c;我最近在做一个项目&#xff0c;感觉代码越来越复杂&#xff0c;我都快看不懂了。尤其是有好几个子系统&#xff0c;它们之间的调用关系让我头疼。 老鸟&#xff1a;复杂的代码确实让人头疼。你有没有考虑过使用设计模式来简化你…