学习体系结构 - AArch64内存管理

学习体系结构 - AArch64内存管理

Learn the architecture - AArch64 memory

management

Version 1.2

个人的英语很一般,对拿不准的翻译校准在后面添加了英文原文。

1、 概述

本指南介绍了AArch64中的内存转换,这是内存管理的关键。它解释了如何将虚拟地址转换为物理地址转换表格式,以及软件如何管理转 换转译后备缓冲器(TLB)

这些信息对于任何正在开发底层代码的人都很有用,比如启动代码或驱动程序。它与任何正在编写设置或管理内存管理单元(MMU)代码的人特别相关。

在本指南的最后,您可以检查您的知识。您将了解如何将虚拟地址转换为物理地址。您将能够命名不同的地址空间,并描述地址空间如何映射到翻译的各个阶段。您还将了解软件何时必须执行TLB维护,以及TLB维护命令的语法。

2、 什么是内存管理?

内存管理描述了如何控制对系统中内存的访问。每次操作系统或应用程序访问内存时,硬件都会执行内存管理。内存管理是一种为应用程序动态分配内存区域的方法。

为什么需要内存管理?

应用程序处理器被设计为运行一个丰富的操作系统,如Linux,并支持虚拟内存系统。在处理器上执行的软件只能看到虚拟地址,而处理器会将其转换为物理地址。这些物理地址被呈现给内存系统,并指向内存中的实际物理位置。

3、虚拟地址和物理地址

使用虚拟地址的好处是,它允许管理软件,如操作系统(OS),来控制呈现给软件的内存的视图。操作系统可以控制什么内存是可见的,该内存是可见的虚拟地址,以及允许对该内存的访问。这允许操作系统能够对应用程序沙盒化(从另一个应用程序中隐藏一个应用程序的资源),并提供来自底层硬件的抽象。

使用虚拟地址的一个好处是,操作系统可以将内存的多个碎片物理区域作为单个连续的虚拟地址空间呈现给应用程序。

虚拟地址也有利于软件开发人员,他们在编写应用程序时将不知道系统的确切内存地址。有了虚拟地址,软件开发人员就不需要关心物理内存了。应用程序知道,应该由操作系统和硬件一起工作执行地址转换。

事实上,每个应用程序都可以使用自己的一组虚拟地址,这些地址将映射到物理系统中的不同位置。随着操作系统在不同的应用程序之间切换时,它会重新编程映射关系。这意味着当前应用程序的虚拟地址将映射到内存中正确的物理位置。虚拟地址通过映射被转换为物理地址。虚拟地址和物理地址之间的映射存储在转换表(有时也称为页表)中,如下图所示:

在这里插入图片描述

转换表在内存中,由软件管理,通常是操作系统或管理程序。翻译表不是静态的,这些表可以根据软件更改的需要进行更新。这将更改虚拟地址和物理地址之间的映射。

4、内存管理单元(MMU)

内存管理单元(MMU)负责将软件使用的虚拟地址转换为内存系统中使用的物理地址。

MMU包含以下内容:

  • 表行走单元(The table walk unit),它包含从内存中读取转换表的逻辑
  • 翻译后备缓冲区(TLBs),它缓存最近使用的翻译

由软件发布的所有内存地址都是虚拟的。这些内存地址被传递给MMU,MMU检查TLB是否有最近使用的缓存转换。如果MMU没有找到最近缓存的转换,表行走单元将从内存中读取适当的表项或条目,如下所示:

在这里插入图片描述

在进行内存访问之前,一个虚拟地址必须被转换为一个物理地址(因为我们必须知道我们正在访问的是哪个物理内存位置)。这种转换的需求也适用于缓存的数据,因为在Armv6和更高版本的处理器上,数据缓存使用物理地址(经过物理标记的地址)来存储数据。因此,在完成缓存查找之前,必须转换地址。

架构是一种行为规范。缓存的行为必须好像它们具有物理标记。实现可能采用不同的方法,只要这不是软件可见的。

表项(Table Entry)

转换表的工作原理是将虚拟地址空间划分为相同大小的Block,并为每个块在表中提供一个 Entry。

表中的 Entry 0 提供 Block 0 的映射,Entry 1提供 Block1 的映射,以此类推。每个条目包含相应的物理内存块的地址以及访问物理地址时使用的属性。

在这里插入图片描述

表查找(Table look up)

当发生转换时会发生表查找。当发生转换时,软件发出的虚拟地址将被一分为二,如图所示:

在这里插入图片描述

此图显示了一个单级查找。

图中标记为 “Which entry” 的高位告诉您要查看哪个块条目,并且它们被用作表中的索引。此输入块包含该虚拟地址的物理地址。

多级转换(Multilevel translation)

在单层查找中,虚拟地址空间被分割成相同大小的块。事实上,使用表的层次结构。

第一个表(Level 1 table)将虚拟地址空间分成大块。这个表中的每个条目都可以指向一个大小相同的物理内存块,也可以指向另一个表,该表将该块细分为更小的块。我们将这种类型的表称为“多层表”。在这里,我们可以看到一个有三个层次的多级表的例子:

在这里插入图片描述

在Armv8-A中,级别的最大数量是4个,级别编号为0到3。

这种多级方法允许描述更大的块和更小的块。大块和小块的特征如下:

  • 大块比小块需要更少的读取级别来翻译。此外,大块在TLB中缓存更有效
  • 小块给出了软件对内存分配的细粒度控制。然而,小块在TLB中缓存的效率较低。缓存效率低是因为小块需要通过级别进行多次读取才能进行翻译。

为了管理这种权衡,操作系统必须平衡使用较大映射的效率和使用较小映射的灵活性,以获得最佳性能。

处理器在启动表查找时并不知道转换的大小。处理器通过执行表行走来计算正在转换的块的大小。

5、 地址空间

在AArch64中有几个独立的虚拟地址空间。此图显示了这些虚拟地址空间:

在这里插入图片描述

该图显示了三个虚拟地址空间:

  • Non-secure EL0 and EL1
  • Non-secure EL2
  • EL3

每个虚拟地址空间都是独立的,并且都有自己的设置和表。我们经常称这些设置和表为“翻译机制”。 Secure EL0、Secure EL1和Secure EL2也有虚拟地址空间,但它们没有显示在图中。

在Armv8.4-A中添加了对Secure EL2的支持。

因为存在多个虚拟地址空间,所以指定地址所在的地址空间很重要。例如,NS.EL2:0x8000是指在 Non-secure EL2虚拟地址空间中的地址0x8000。

该图还显示了来自 Non-secure EL0和Non-secure EL1的虚拟地址都经过了两组表。这些表支持虚拟化,并允许虚拟机管理程序(hypervisor)虚拟化虚拟机(VM)所看到的物理内存的视图。

Armv9-A支持上述针对Armv8-A的所有虚拟地址空间。Armv9-A引入了可选的领域管理扩展(RME)。当实现RME时,还存在额外的翻译机制:

  • Realm EL1 and EL0
  • Realm EL2 and EL0
  • Realm EL2

在虚拟化中,我们称由操作系统控制的翻译称为Stage 1。Stage 1的表将虚拟地址转换为中间物理地址(IPAs)。在阶段1中,操作系统认为IPA是物理地址空间。然而,管理程序监控程序(hypervisor)控制着第二组翻译,我们称之为Stage 2。这第二组翻译将IPA转换为物理地址。此图显示了这两组翻译的工作原理:

在这里插入图片描述

虽然在表格格式上有一些细微的差异,但Stage 1和Stage 2的翻译过程通常是相同的。

在Arm中,我们在许多示例中都使用了地址0x8000。0x8000也是使用Arm链接器(armlink)进行链接的默认地址。这个地址来自一台早期的微型计算机,BBC Micro Model B,它在地址0x8000处有ROM(和侧面的RAM)。BBC Micro Model B是由一家名为Acorn的公司建造的,该公司开发了Acorn RISC Machine(ARM),后来成为Arm。

物理地址(Physical Addresses)

除了多个虚拟地址空间外,AArch64还具有多个物理地址空间(PAS):

  • Non-secure PAS0
  • Secure PAS
  • Realm PAS
  • Realm PAS(Armv9-A only)
  • Root PAS(Armv9-A only)

虚拟地址可以映射到哪个物理地址空间取决于处理器的当前安全状态。下面的列表显示了安全状态及其对应的虚拟地址映射目标:

  • Non-secure state:虚拟地址只能映射到 Non-scure 的物理地址
  • Secure state:虚拟地址可以映射到 Secure 或 Non-secure 的物理地址
  • Realm state:虚拟地址可以映射到 Realm 或 Non-secure 的物理地址
  • Root state:虚拟地址可以映射到任何物理地址空间。

当处于具有多个物理地址空间可见性的安全状态时,转换表条目控制使用哪个输出的物理地址空间。下图显示了多个物理地址空间的映射:

在这里插入图片描述

地址大小(Address sizes)

AArch64是一个64位的架构,但这并不意味着所有的地址都是64位的。

虚拟地址的大小

虚拟地址以64位的格式存储。因此,加载指令(LDR)和存储指令(STR)中的地址总是在 X寄存器 中指定。然而,并非X寄存器中的所有地址都有效。

此图显示了AArch64中的虚拟地址空间的布局:
在这里插入图片描述

EL0/EL1虚拟地址空间有两个区域:内核空间和应用程序空间。这两个区域显示在图的左侧,内核空间在顶部,应用程序空间被标记为“User Space”,在地址空间的底部。内核空间和用户空间有单独的转换表,这意味着它们的映射可以保持独立。

在所有其他异常级别的地址空间的底部有一个单个区域。这个区域显示在图表的右侧,是一个没有文本的方框。

如果将HCR_EL2.E2H设置为1,则将启用主机操作系统在EL2中运行的配置,以及主机操作系统的应用程序在EL0中运行的配置。在这种情况下,EL2也有一个上区域和一个下区域。

地址空间的每个区域具有可达52位的大小。然而,每个区域都可以独立地缩小到一个更小的尺寸。TCR_ELx寄存器中的TnSZ字段控制着虚拟地址空间的大小。例如,此图显示了TCR_EL1控制EL0/EL1虚拟地址空间:

在这里插入图片描述

虚拟地址大小编码为:

virtual address size in bytes = 264-TCR_ELx.TnSZ

虚拟地址的大小也可以表示为地址位的数量:

Number of address bits = 64 - TnSZ

因此,如果TCR_EL1.SZ1被设置为32,EL0/EL1虚拟地址空间中的内核区域的大小为232字节(0xFFFF_FFFF_0000_0000到0xFFFF_FFFF_FFFF_FFFF)。任何超出配置范围的地址在访问时将产生异常。这种配置的优点是,我们只需要描述尽可能多的地址空间,这就节省了时间和空间。例如,假设OS内核需要1GB的地址空间(30位的地址大小)来实现其内核空间。如果操作系统将T1SZ设置为34,则只创建描述1GB的翻译表条目,如64 - 34 = 30。

所有的Armv8-A实现都支持48位的虚拟地址。支持52位虚拟地址是可选的,并由ID_AA64MMFR2_EL1报告。在编写时,还没有一个Arm Cortex-A处理器支持52位虚拟地址。

物理地址的大小

物理地址的大小是实现定义(IMPLEMENTATION DEFINED)的,最多52位。ID_AA64MMFR0_EL1寄存器报告由处理器实现的大小。对于Arm Cortex-A处理器,这通常是40位或44位。

在Armv8.0-A中,一个物理地址的最大大小是48位。这在Armv8.2-A中被扩展到52位。

中间物理地址的大小

如果您在转换表条目中指定的输出地址大于已实现的最大值,则内存管理单元(MMU)将产生一个异常作为地址大小错误。

IPA空间的大小可以进行与虚拟地址空间相同的配置。VTCR_EL2.T0SZ控制大小。可以配置的最大大小与处理器支持的物理地址大小相同。这意味着您不能配置比所支持的物理地址空间更大的IPA空间。

地址空间标识符 - 使用已拥有的进程来标记翻译

许多现代操作系统的应用程序似乎都运行在同一个地址区域,这就是我们所描述的用户空间。事实上,不同的应用程序需要不同的映射。这意味着,例如,VA 0x8000的翻译取决于当前正在运行的哪个应用程序。

理想情况下,我们希望不同应用程序的翻译在翻译后备缓冲区(TLBs)中共存,以防止在上下文切换上需要TLB失效。但是处理器如何知道要使用哪个版本的VA 0x8000翻译呢?在Armv8-A中,答案是地址空间标识符(ASID)。

对于EL0/EL1虚拟地址空间,可以使用转换表项的属性字段中的nG位将转换标记为全局(G)或非全局(nG)。例如,内核映射是全局翻译,而应用程序映射是非全局翻译。全局翻译应用于当前正在运行的任何应用程序。非全局翻译仅适用于特定的应用程序。

非全局映射在TLB中用ASID进行标记。在TLB查找中,将TLB条目中的ASID与当前选择的ASID进行比较。如果它们不匹配,则不使用该TLB条目。此图显示了内核空间中没有ASID标记的全局映射和用户空间中带有ASID标记的非全局映射:

在这里插入图片描述

该图显示,多个应用程序的TLB条目允许在缓存中共存,并且ASID决定使用哪个条目。

ASID存储在两个TTBRn_EL1寄存器中的一个。TTBR0_EL1通常用于用户空间。因此,单个寄存器更新可以同时更改ASID和它所指向的转换表。

ASID标记也可以在EL2中使用,当HCR_EL2.E2H==1。

虚拟机标识符 - 使用所拥有的虚拟机来标记翻译

EL0/EL1翻译也可以用虚拟机标识符(VMID)进行标记。VMIDs 允许来自不同VM的翻译在缓存中共存。这类似于ASIDs 对翻译来自不同应用程序的工作方式。事实上,这意味着一些翻译将同时被标记为VMID和ASID,并且两者都必须匹配才能使用TLB条目。

当安全状态支持虚拟化时,EL0/EL1翻译总是用VMID标记,即使没有启用Stage 2翻译。这意味着,如果您正在编写初始化代码而没有使用系统管理程序(hypervisor),那么在设置Stage 1 MMU之前设置一个已知的VMID值是很重要的。

通用非私有 Common not Private

如果一个系统包含多个处理器,那么在一个处理器上使用的ASID和VMID在其他处理器上是否具有相同的含义?

对于Armv8.0-A,答案是它们不必意味着相同的东西。不要求软件在多个处理器上以相同的方式使用给定的ASID。例如,ASID 5 可能被一个处理器上的计算器使用,可能被另一个处理器上的web浏览器使用。这意味着由一个处理器创建的 TLB 条目不能被另一个处理器使用。

事实上,软件不太可能在不同的处理器之间使用不同的 ASIDs。软件在给定系统中的所有处理器上以相同的方式使用 ASIDs 和 VMIDs 更为常见。因此,Armv8.2-A在转换表基寄存器(TTBR)中引入了通用非私有(CnP)位。当设置了CnP位时,该软件承诺在所有处理器上以相同的方式使用 ASIDs 和 VMIDs ,这允许由一个处理器创建的 TLB 条目被另一个处理器使用。

我们一直在谈论处理器,但是,从技术上讲,我们应该使用 Process Element(PE)这个术语。PE是对实现Arm架构的任何机器的通用术语。这很重要,因为在处理器之间共享 TLB 是困难的。但是在一个多线程处理器中,每个硬件线程都是一个 PE,它更希望共享 TLB 条目。

6、 控制地址转换和转换表的格式

在这里,我们可以看到翻译表条目所允许的不同格式:

在这里插入图片描述

为了清晰起见,此图没有指定位字段的宽度。您可以在 Arm Architecture Reference Manual Armv8, for Armv8-A architecture profile: The VMSAv8-64 translation table format descriptors 中找到这个信息。

每个条目是64位,底部的两个位决定了条目的类型。

请注意,某些表条目仅在特定的级别上有效。表的最大级别数为4个,这就是为什么没有针对 Level 3(或第四级)表的表描述符的原因。类似地,Level 0中也没有块描述符或页面描述符。因为Level 0条目覆盖了很大的虚拟地址空间区域,所以允许块没有意义。

Levels 0 - 2 的表描述符的编码与 Level 3 的页面描述符相同。这种编码允许“递归表”,它们指向它们自己。这很有用,因为它便于计算特定页表条目的虚拟地址,以便可以更新它。

7、 翻译颗粒

翻译颗粒是可以描述的最小的内存块。没有更小的可以描述,只有更大的块,这是颗粒的倍数。

AArch64支持三种不同的颗粒尺寸: 4KB、16KB和64KB。

处理器所支持的颗粒大小是由 ID_AA64MMFR0_EL1 定义并报告的实现。所有的 Arm Cortex-A 处理器都支持4KB和64KB。所选的颗粒是在最新级别表中可以描述的最小块。也可以描述更大的块。此表显示了基于所选颗粒的每个级别表的不同块大小:

在这里插入图片描述

在引入 Armv9.2-A 和 Armv8.7-A 之前,对使用52位地址有限制。当所选颗粒为4KB或16KB时,最大虚拟地址区域大小为48位。同样地,输出物理地址被限制为48位。只有当使用64KB的颗粒时,才能使用完整的52位。

TCR_EL1 有两个独立的字段来控制内核空间的颗粒大小和用户空间的虚拟地址范围。这些字段对于内核空间称为TG1,对于用户空间称为TG0。程序员面临的一个潜在问题是,这两个字段有不同的编码。

地址转换的起始级别

颗粒和虚拟地址空间的大小一起控制着地址转换的起始级别。

上一个表总结了每级表中每个颗粒的块大小(由单个条目所覆盖的虚拟地址范围的大小)。从块的大小中,您可以计算出虚拟地址的哪些位被用来索引表的每个级别。

让我们以4KB的颗粒为例。此图显示了用于索引一个4KB颗粒的不同级别表的位:

在这里插入图片描述

假设,对于一个配置,您将虚拟地址空间的大小 TCR_ELx.T0SZ 设置为32。然后虚拟地址空间的大小,以地址位计算,计算为:

64-T0SZ = 32 位地址空间(地址位31:0)

如果我们再看前面的4KB颗粒图,Level 0被位 47:39 索引。对于一个32位的地址空间,你就没有这些位了。因此,您的配置的初始转换级别是 Level 1。

接下来,假设您将 T0SZ 设置为 34:

64-T0SZ = 30 位地址空间(地址位29:0)

这次,您没有任何用于索引 Level 0 表或 Level 1 表的其他位,因此配置的初始转换级别为Level 2 。

如上图所示,当虚拟地址空间的大小减小时,您需要更少级别的表来描述它。

这些例子是基于使用 4KB 的颗粒。同样的原理也适用于使用16KB和64KB的颗粒,但地址位发生了变化。

控制地址转换的寄存器

地址转换由以下系统寄存器的组合控制:

  • SCTLR_ELx

    M - 启用内存管理单元(MMU)

    C - 启用数据和统一缓存

    EE - 翻译表行走的字节顺序

  • TTBR0_ELx 和 TTBR1_ELx

    BADDR - 翻译表开始位置的物理地址(PA)(或中间物理地址,EL0/EL1)

    ASID - 用于非全局转换的地址空间标识符

  • TCR_ELx

    PS/IPS - PA或IPA空间的大小,最大输出地址大小

    TnSZ - 表中所覆盖的地址空间的大小

    TGn - 颗粒大小

    SH/IRGN/ORGN - MMU表行走所使用的可访问性和可共享性

    TBln - 禁用表行走到特定的表

  • MAIR_ELx

    Attr - 控制 Stage1 表中的类型和可缓存性。

MMU 禁用

当在翻译阶段禁用MMU时,所有地址都是平面映射的。平面映射表示输入地址和输出地址相同。

8、 翻译后备缓冲区(TLBs)的维护

翻译后备缓冲区(TLBs)缓存最近使用的翻译。这种缓存允许在后续查找中翻译被再次使用,而不需要重读表。

TLBs 是翻译的缓存,而不是翻译表的缓存。区别是微妙的。有几个寄存器字段控制如何解释翻译表条目。TLB 条目中包含的是根据表被遍历时的配置所给出的翻译表条目的解释。在Arm架构参考手册(Arm ARM)中,这样的寄存器字段被描述为 “允许在TLB中缓存”。

如果更改了转换表条目或影响条目解释方式的控件,则需要使TLB中受影响的条目无效。如果您不使这些条目无效,那么处理器可能会继续使用旧的翻译。

处理器不允许缓存到导致以下任何故障的TLB的转换:

  • 转换故障(未映射的地址)
  • 地址大小错误(地址超出范围)
  • 访问标志故障

因此,在第一次映射地址时,不需要发出TLB无效。但是,如果您想执行以下任何操作,则需要发出一个TLB无效:

  • 取消映射地址

    获取一个以前有效的地址或已映射的地址,并将其标记为错误地址。

  • 更改一个地址的映射

    更改输出地址或任何属性。例如,将地址从只读权限更改为读写权限。

  • 更改解释表的方式

    这种情况并不常见。但是,例如,如果颗粒大小改变了,那么对表的解释也会改变。因此,一个TLB无效将是必要的。

TLB操作的格式

TLBI 指令用于使 TLBs 中的条目无效。此指令的语法为:

TLBI < type >< level >{IS|OS} {, < xt >}

其中,

  • < type >,哪些条目无效

    All - 所有条目

    VA - 匹配在 Xt 的 VA 和 ASID 的条目 [ Entry matching VA and ASID in Xt ]

    VAA - 匹配在 Xt 中的 VA ,任何 ASID 的条目

    ASID - 匹配在 Xt 中的 ASID 的任何条目

    更多

  • < level >,要操作的地址空间

    E1 = EL0/1虚拟地址空间

    E2 = EL2虚拟地址空间

    E3 = EL3虚拟地址空间

  • < IS|OS >,无论一个操作是内部可共享(IS)还是外部可共享(OS)

    当 IS 添加到操作时,它将广播到内部共享域中的其他核心

    当 OS 添加到操作时,它将广播到外部共享域的其他核心(在Armv8.4-A中添加)

  • < Xt >,操作哪个地址或ASID

    仅用于按地址或ASID进行的操作

例如,考虑一个正在更新其内核转换表中的条目的操作系统(OS)。一个典型的 TLB 无效序列应该是这样的:

STR X1, [X5] 		// Write to translation table entry
DSB ISH 			// Barrier instructions - not covered in this guide
TLBI VAAE1IS , X0 	// Invalidate VA specified by X0, in EL0/1// virtual address space for all ASIDs
DSB ISH 			// Barrier instructions - not covered in this guide
ISB 				// Synchronize context on this processor

9、 地址翻译指令

地址转换(AT)指令允许软件查询特定地址的翻译。将翻译结果以及其属性写入到物理地址寄存器 PAR_EL1 中

AT指令的语法允许您指定要使用的翻译机制。例如,EL2可以查询EL0/EL1的翻译机制。但是,EL1不能使用AT指令来查询EL2的转换机制,因为这是对违反特权的。

如果所请求的翻译会导致错误,则不会生成异常。相反,将生成的故障类型将记录在 PAR_EL1 中。

10、 检查你的知识

Q:地址翻译的 stage 和 level 有什么区别?

A:Stage 是将输入地址转换为输出地址的过程。对于 Stage 1,这是从 VA 到 IPA 的过程,对于Stage 2,从 IPA 到 PA 的过程。Level 指的是给定翻译阶段的表。这也是如何将更大的块细分为更小的块。

Q:一个物理地址的最大大小是多少?

A:物理地址空间的最大大小是 IMPLEMENTATION DEFINED,最多52位(自Armv8.2-A)。

Q:哪个寄存器字段控制虚拟地址空间的大小?

A:TCR_ELx.TnSZ,或 VTCR_EL2.T0SZ 为 Stage 2。

Q:什么是翻译颗粒,支持的尺寸是多少?

A:它是可以描述的最小的内存块。支持的尺寸分别为4KB、16KB和64KB。

Q:TLBI 的 ALLE3 是做什么的?

A:它会使EL3虚拟地址空间中的所有TLB条目无效。

Q:导致翻译故障的翻译表项能否缓存在TLB中?

A:不,它不能存储在TLBs中。

Q:当禁用MMU时,地址将如何映射?

A:地址是平面映射的,因此输入地址和输出地址是相同的。

Q:什么是 ASID ?什么时候 TLB 条目包含一个 ASID ?

A:ASID 是一个地址空间标识符,它标识与翻译关联的应用程序。非全局映射(nG=1)在 TLBs 中用 ASID 进行标记。

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

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

相关文章

Redis内存使用率高,内存不足问题排查和解决

问题现象 表面现象是系统登录突然失效&#xff0c;排查原因发现&#xff0c;使用redis查询用户信息异常&#xff0c;从而定位到redis问题 if (PassWord.equals(dbPassWord)) {map.put("rtn", 1);map.put("value", validUser);session.setAttribute("…

决策规划框架 - (解耦:路径规划和速度规划 | 耦合:行为规划和轨迹规划)

1 解耦策略 1.1 概述 核心思想&#xff1a; &#xff08;1&#xff09;路径规划&#xff1a;假定环境是“静态的”&#xff0c;将障碍物投影到参考路径上&#xff0c;并规划路径避开这些障碍物 &#xff08;2&#xff09;速度规划&#xff1a;根据路径规划给出的路径&#xf…

使用poi将pptx文件转为图片详解

目录 项目需求 后端接口实现 1、引入poi依赖 2、代码编写 1、controller 2、service层 测试出现的bug 小结 项目需求 前端需要上传pptx文件&#xff0c;后端保存为图片&#xff0c;并将图片地址保存数据库&#xff0c;最后大屏展示时显示之前上传的pptx的图片。需求看上…

图文证明 泰勒公式展开

泰勒公式 泰勒公式简单来说就是,可以用一个N次多项式来表示出一个连续可导的函数 f(x) 是一个用函数在某点的信息描述其附近取值的公式 第一步 思考 这是一个sin(x)的图像 用函数在原点的信息描述其附近取值 用一阶导数贴合: 直接用切线来贴合就好 画一个点(0,sin(0)除的切…

Q-Tester:适用于开发、生产和售后的诊断测试软件

Q-Tester.Expert是一款基于ODX&#xff08;ASAM MCD-2D / ISO 22901-1&#xff09;国际标准的工程诊断仪。通过此诊断仪可实现与ECU控制器之间的数据交互。这一基于ODX国际标准的解决方案&#xff0c;其优势在于&#xff1a;ODX数据库不仅可在开发部门交互&#xff0c;而且可在…

浅谈WAF——守护网络安全的无形之盾

随着信息化时代的到来&#xff0c;网络已逐渐融入我们日常生活的方方面面。然而&#xff0c;与此同时&#xff0c;网络安全问题却也如影随形。为此&#xff0c;一种名为“Web应用防火墙”的工具应运而生&#xff0c;简称"WAF"。 WAF是什么&#xff1f; WAF&#xf…

【RDMA】rdma-core驱动源码包|ibverbs|rdmacm

目录 源码包 编译 用法 驱动包内的例子 其他 源码包 mellanox的rdma驱动源码包形式如下&#xff1a; MLNX_OFED_LINUX-5.8-1.1.2.1-rhel9.0-ext/src/MLNX_OFED_SRC-5.8-1.1.2.1/SRPMS rdma-core-58mlnx43-1.58112.src.rpm rpm -ivh rdma-core-58mlnx43-1.58112.src.rpm 安装完…

前端基础:Vue搞笑白话文(工作之余瞎写)

1、data:{}与data(){return{}}这两个是个什么鬼&#xff1f; vue实例 new Vue({el:#app,data:{name:李四}}) 组件实例 const aaa Vue.extent({data(){return {name:}} }) 为什么Vue实例可以那么写而组件实例就不行了&#xff1f;原因就是因为在底层原理上&#xff0c;组件…

VSCode团队工程实践:通过名称混淆将代码大小减少了20%

​我们最近将Visual Studio Code的JavaScript代码大小减少了20%。这相当于节省了3.9 MB多一点的空间。当然&#xff0c;这比我们发布说明中的一些单个gif图片的大小要少&#xff0c;但这仍然十分可观。这种减少不仅意味着您需要下载和存储在磁盘上的代码更少&#xff0c;而且还…

蓝桥杯C/C++程序设计——成绩统计

题目描述 小蓝给学生们组织了一场考试&#xff0c;卷面总分为 100 分&#xff0c;每个学生的得分都是一个 0 到 100 的整数。 如果得分至少是 60 分&#xff0c;则称为及格。如果得分至少为 85 分&#xff0c;则称为优秀。 请计算及格率和优秀率&#xff0c;用百分数表示&am…

Git 常用命令知识笔记

Git 仓库数据结构 Git 仓库由一个个的 commit 组成某些 commit 上会有一些 branch 指向它们&#xff0c;这些 branch 的本质是引用有一个特殊的引用叫做 HEAD&#xff0c;它始终指向当前的位置&#xff0c;这个位置可以是 commit&#xff0c;也可以是 branch staging area 暂存…

政务大数据能力平台建设方案:文件全文30页,附下载

关键词&#xff1a;智慧政务解决方案&#xff0c;智慧政务建设&#xff0c;智慧政务服务平台&#xff0c;智慧政务大数据&#xff0c;数字政务一体化平台。大数据&#xff0c;政务大数据建设 一、智慧政务建设需求 1、政务服务需求&#xff1a;智慧政务建设需要满足人民群众的…