《操作系统导论》第16章读书笔记:分段

《操作系统导论》第16章读书笔记:分段

效果图

效果图

—— 杭州 2024-03-31 夜


文章目录

  • 《操作系统导论》第16章读书笔记:分段
    • 0.前言
    • 1.分段:泛化的基址/界限
    • 2.我们引用哪个段?
    • 3.栈怎么办
    • 4.支持共享
    • 5.细粒度与粗粒度的分段、操作系统支持
    • 6.小结
    • 7.补充笔记:地址空间和进程空间的关系
    • 8.补充笔记:一个CPU有几个基址寄存器和界限寄存器?一个CPU有几个地址空间和进程空间?一个CPU有几个MMU?

0.前言

到目前为止,我们一直假设将所有进程的地址空间完整地加载到内存中。利用基址和界限寄存器,操作系统很容易将不同进程重定位到不同的物理内存区域。但是,对于这些内存区域,你可能已经注意到一件有趣的事:栈和堆之间,有一大块“空闲”空间。

从图 16.1 中可知,如果我们将整个地址空间放入物理内存,那么栈和堆之间的空间并没有被进程使用,却依然占用了实际的物理内存。因此,简单的通过基址寄存器和界限寄存器实现的虚拟内存很浪费。另外,如果剩余物理内存无法提供连续区域来放置完整的地址空间,进程便无法运行。这种基址加界限的方式看来并不像我们期望的那样灵活。因此:

关键问题:怎样支持大地址空间?
怎样支持大地址空间,同时栈和堆之间(可能)有大量空闲空间?在之前的例子里,地址空间非常小,所以这种浪费并不明显。但设想一个 32 位(4GB)的地址空间,通常的程序只会使用几兆的内存,但需要整个地址空间都放在内存中。

在这里插入图片描述

1.分段:泛化的基址/界限

  • 分段:这个想法很简单,在MMU 中引入不止一个基址和界限寄存器对,而是给地址空间内的每个逻辑段(segment)一对。一个段只是地址空间里的一个连续定长的区域在典型的地址空间里有3个逻辑不同的段:代码、栈和堆。分段的机制使得操作系统能够将不同的段放到不同的物理内存区域,从而避免了虚拟地址空间中的未使用部分占用物理内存。

  • 稀疏地址空间,sparse address spaces:如图16.2所示,64KB的物理内存中放置了3个段(为操作系统保留16KB)。从图中可以看到,只有已用的内存才在物理内存中分配空间,因此可以容纳巨大的地址空间,其中包含大量未使用的地址空间(有时又称为稀疏地址空间,sparse address spaces)。

  • 段错误:段错误指的是在支持分段的机器上发生了非法的内存访问。有趣的是,即使在不支持分段的机器上
    这个术语依然保留。

  • 段异常(segmentation violation)或段错误(segmentation fault):如果我们试图访问非法的地址,例如7KB,它超出了堆的边界呢?你可以想象发生的情况:硬件会发现该地址越界,因此陷入操作系统,很可能导致终止出错进程。这就是每个C 程序员都感到恐慌的术语的来源。

// 假设:基址寄存器值为 32KB(即 32768 字节),界限寄存器值为 2KB(即 2048 字节)// 虚拟地址转换为物理地址的函数
function 虚拟地址转物理地址(虚拟地址, 基址寄存器, 界限寄存器) {// 越界检查if (虚拟地址 >= 界限寄存器) {抛出异常("段错误"); // 越界访问} else {// 计算物理地址并返回物理地址 = 虚拟地址 + 基址寄存器;return 物理地址;}
}// 示例 1: 虚拟地址 100 的转换
物理地址 = 虚拟地址转物理地址(100, 32768, 2048);
// 物理地址应该是 32868// 示例 2: 堆中的地址 4200 的转换
// 假设堆基址寄存器值为 34KB(即 34816 字节),界限寄存器值为 2KB
物理地址 = 虚拟地址转物理地址(4200 - 4096, 34816, 2048); // 偏移量是 4200 - 4096
// 物理地址应该是 34920// 越界检查示例
try {虚拟地址转物理地址(4400, 32768, 2048); // 假设这是一个非法地址,因为它超出了界限
} catch (异常 e) {打印("异常: " + e); // 捕获到越界异常
}

在这里插入图片描述

在这里插入图片描述

2.我们引用哪个段?

  • 硬件在地址转换时使用段寄存器。它如何知道段内的偏移量,以及地址引用了哪个段?
  • 一种常见的方式,有时称为显式(explicit)方式,就是用虚拟地址的开头几位来标识不同的段。
  • 在我们的例子中,如果前两位是00,硬件就知道这是属于代码段的地址,因此使用代码段的基址和界限来重定位到正确的物理地址。如果前两位是01,则是堆地址,对应地,使用堆的基址和界限。
  • 前两位(01)告诉硬件我们引用哪个段。剩下的12 位是段内偏移:0000 0110 1000(即十六进制0x068 或十进制104)。因此,硬件就用前两位来决定使用哪个段寄存器,然后用后12位作为段内偏移。偏移量与基址寄存器相加,硬件就得到了最终的物理地址。
  • 请注意,偏移量也简化了对段边界的判断。我们只要检查偏移量是否小于界限,大于界限的为非法地址
  • 上面使用两位来区分段,但实际只有3个段(代码、堆、栈),因此有一个段的地址空间被浪费。因此有些系统中会将堆和栈当作同一个段,因此只需要一位来做标识。
  • 硬件还有其他方法来决定特定地址在哪个段。在隐式(implicit)方式中,硬件通过地址产生的方式来确定段。例如,如果地址由程序计数器产生(即它是指令获取),那么地址在代码段。如果基于栈或基址指针,它一定在栈段。其他地址则在堆段。
  • 如果基址和界限放在数组中(每个段一项),为了获得需要的物理地址,硬件会做下面这样的事:
1    // 获取14位虚拟地址(VA)的前2位
2    Segment = (VirtualAddress & SEG_MASK) >> SEG_SHIFT
3    
4    // 现在获取偏移量
5    Offset  = VirtualAddress & OFFSET_MASK
6    
7    // 如果偏移量超出了段的界限
8    if (Offset >= Bounds[Segment])
9        RaiseException(PROTECTION_FAULT) // 抛出保护故障异常
10   else
11       PhysAddr = Base[Segment] + Offset // 计算物理地址
12       Register = AccessMemory(PhysAddr) // 从物理地址访问内存,并将数据存入寄存器

在这里插入图片描述

3.栈怎么办

  • 它反向增长,地址转换必须有所不同。
  • 需要一点硬件支持。除了基址和界限外,硬件还需要知道段的增长方向(用一位区分,比如1代表自小而大增长,0 反之)。
  • 例程1:
# 定义段寄存器的值,这里仅以栈的信息为例
# 假设栈的基址为28KB,大小为2KB
SEGMENT_BASE_STACK = 28 * 1024  # 栈段的基址(28KB转换为字节)
SEGMENT_SIZE_STACK = 2 * 1024   # 栈段的大小(2KB转换为字节)# 虚拟地址转换函数
def convert_stack_virtual_to_physical(virtual_address):# 如果虚拟地址不在栈的界限内,触发保护故障异常if virtual_address >= SEGMENT_SIZE_STACK:raise Exception("保护故障:虚拟地址超出了栈的界限")# 计算物理地址:基址 + 虚拟地址(偏移量)physical_address = SEGMENT_BASE_STACK + virtual_addressreturn physical_address# 示例:对栈内的虚拟地址进行转换
try:# 假设要转换的栈虚拟地址为1500字节偏移量virtual_address = 1500# 调用函数进行转换physical_address = convert_stack_virtual_to_physical(virtual_address)# 打印转换后的物理地址print("物理地址:", physical_address)
except Exception as e:# 捕获并打印异常信息print(str(e))
  • 例程2:
// 假设:每个段有一个基址(Base)和界限(Limit)寄存器,以及一个反向增长标志(GrowDown)// 段寄存器的数组,每个段一个寄存器,包含基址、界限和反向增长标志
SegmentRegisters = [{ Base: 32KB, Limit: 2KB, GrowDown: false }, // 代码段{ Base: 34KB, Limit: 2KB, GrowDown: false }, // 堆段{ Base: 28KB, Limit: 2KB, GrowDown: true }   // 栈段
]// 虚拟地址转换为物理地址的函数
function 虚拟地址转物理地址(虚拟地址, 段寄存器) {// 计算段内偏移量偏移量 = 虚拟地址 % 段的大小// 根据段是否反向增长调整偏移量if (段寄存器.GrowDown) {偏移量 = 段寄存器.Limit - 偏移量 - 1}// 越界检查if (偏移量 < 0 || 偏移量 >= 段寄存器.Limit) {抛出异常("段错误"); // 越界访问} else {// 计算物理地址并返回物理地址 = 段寄存器.Base + 偏移量return 物理地址}
}// 示例: 虚拟地址 100 的转换(假设在代码段)
物理地址 = 虚拟地址转物理地址(100, SegmentRegisters[代码段])
// 物理地址应该是 100 + 32KB = 32868// 示例: 虚拟地址 4200 的转换(假设在堆段)
物理地址 = 虚拟地址转物理地址(4200 - 4KB, SegmentRegisters[堆段])
// 物理地址应该是 104 + 34KB = 34920// 越界检查示例
try {虚拟地址转物理地址(4400, SegmentRegisters[堆段]) // 假设这是一个非法地址,因为它超出了界限
} catch (异常 e) {打印("异常: " + e) // 捕获到越界异常
}

在这里插入图片描述

4.支持共享

  • 具体来说,要节省内存,有时候在地址空间之间共享(share)某些内存段是有用的。尤其是,代码共享很常见,今天的系统仍然在使用。
  • 保护位(protection bit):为了支持共享,需要一些额外的硬件支持,这就是保护位(protection bit)。基本为每个段增加了几个位,标识程序是否能够读写该段,或执行其中的代码。通过将代码段标记为只读,同样的代码可以被多个进程共享,而不用担心破坏隔离。虽然每个进程都认为自己独占这块内存,但操作系统秘密地共享了内存,进程不能修改这些内存,所以假象得以保持。
  • 表16.3 展示了一个例子,是硬件(和操作系统)记录的额外信息。可以看到,代码段的权限是可读和可执行,因此物理内存中的一个段可以映射到多个虚拟地址空间。
  • 有了保护位,前面描述的硬件算法也必须改变。除了检查虚拟地址是否越界,硬件还需要检查特定访问是否允许。如果用户进程试图写入只读段,或从非执行段执行指令,硬件会触发异常,让操作系统来处理出错进程。

在这里插入图片描述

5.细粒度与粗粒度的分段、操作系统支持

  • 到目前为止,我们的例子大多针对只有很少的几个段的系统(即代码、栈、堆)。我们可以认为这种分段是粗粒度的(coarse-grained),因为它将地址空间分成较大的、粗粒度的块。但是,一些早期系统(如Multics[CV65,DD68])更灵活,允许将地址空间划分为大量较小的段,这被称为细粒度(fine-grained)分段

  • 支持许多段需要进一步的硬件支持,并在内存中保存某种段表(segment table)。这种段表通常支持创建非常多的段,因此系统使用段的方式,可以比之前讨论的方式更灵活。例如,像Burroughs B5000 这样的早期机器可以支持成千上万的段,有了操作系统和硬件的支持,编译器可以将代码段和数据段划分为许多不同的部分[RK68]。当时的考虑是,通过更细粒度的段,操作系统可以更好地了解哪些段在使用哪些没有,从而可以更高效地利用内存。

  • 系统运行时,地址空间中的不同段被重定位到物理内存中。与我们之前介绍的整个地址空间只有一个基址/界限寄存器对的方式相比,大量节省了物理内存。具体来说,栈和堆之间没有使用的区域就不需要再分配物理内存,让我们能将更多地址空间放进物理内存。

  • 然而,分段也带来了一些新的问题。我们先介绍必须关注的操作系统新问题。第一个是老问题:操作系统在上下文切换时应该做什么?你可能已经猜到了:各个段寄存器中的内容必须保存和恢复。显然,每个进程都有自己独立的虚拟地址空间,操作系统必须在进程运行前,确保这些寄存器被正确地赋值。

  • 第二个问题更重要,即管理物理内存的空闲空间。新的地址空间被创建时,操作系统需要在物理内存中为它的段找到空间。之前,我们假设所有的地址空间大小相同,物理内存可以被认为是一些槽块,进程可以放进去。现在,每个进程都有一些段,每个段的大小也可能不同。

  • 一般会遇到的问题是,物理内存很快充满了许多空闲空间的小洞,因而很难分配给新的段,或扩大已有的段。这种问题被称为·外部碎片(external fragmentation)[R69],如图16.3(左边)所示。

  • 在这个例子中,一个进程需要分配一个20KB 的段。当前有24KB 空闲,但并不连续(是3个不相邻的块)。因此,操作系统无法满足这个20KB 的请求。

  • 该问题的一种解决方案是紧凑(compact)物理内存,重新安排原有的段。例如,操作系统先终止运行的进程,将它们的数据复制到连续的内存区域中去,改变它们的段寄存器中的值,指向新的物理地址,从而得到了足够大的连续空闲空间。这样做,操作系统能让新的内存分配请求成功。但是,内存紧凑成本很高,因为拷贝段是内存密集型的,一般会占用大量的处理器时间。图16.3(右边)是紧凑后的物理内存。

  • 一种更简单的做法是利用空闲列表管理算法,试图保留大的内存块用于分配。相关的算法可能有成百上千种,包括传统的最优匹配(best-fit,从空闲链表中找最接近需要分配空间的空闲块返回)、最坏匹配(worst-fit)、首次匹配(first-fit)以及像伙伴算法(buddy algorithm)[K68]这样更复杂的算法。Wilson等人做过一个很好的调查[W+95],如果你想对这些算法了解更多,可以从它开始,或者等到第17章,我们将介绍一些基本知识。但遗憾的是,无论算法多么精妙,都无法完全消除外部碎片,因此,好的算法只是试图减小它。

在这里插入图片描述

6.小结

分段解决了一些问题,帮助我们实现了更高效的虚拟内存。不只是动态重定位,通过避免地址空间的逻辑段之间的大量潜在的内存浪费,分段能更好地支持稀疏地址空间。它还很快,因为分段要求的算法很容易,很适合硬件完成,地址转换的开销极小。分段还有一个附加的好处:代码共享如果代码放在独立的段中,这样的段就可能被多个运行的程序共享

但我们已经知道,在内存中分配不同大小的段会导致一些问题,我们希望克服。首先,是我们上面讨论的外部碎片由于段的大小不同,空闲内存被割裂成各种奇怪的大小,因此满足内存分配请求可能会很难。用户可以尝试采用聪明的算法[W+95],或定期紧凑内存,但问题很根本,难以避免。

第二个问题也许更重要,分段还是不足以支持更一般化的稀疏地址空间。例如,如果有一个很大但是稀疏的堆,都在一个逻辑段中,整个堆仍然必须完整地加载到内存中。换言之,如果使用地址空间的方式不能很好地匹配底层分段的设计目标,分段就不能很好地工作。因此我们需要找到新的解决方案。你准备好了吗?

在这里插入图片描述

7.补充笔记:地址空间和进程空间的关系

地址空间和进程空间是两个相关但不同的概念,它们在操作系统中以不同的方式被管理和使用。

  1. 地址空间

    地址空间通常指的是一个处理器可以寻址的全部内存范围。在32位系统中,地址空间通常是4GB(2的32次方),在64位系统中则远远大于此数值。地址空间包括了所有可能的地址,这些地址可以是物理内存地址,也可以是虚拟内存地址。

    • 物理地址空间:是指CPU通过其地址引脚直接访问的内存(RAM、ROM、映射的I/O等)的范围。
    • 虚拟地址空间:是指通过虚拟内存管理,操作系统提供给应用程序和进程的一套地址,这些地址会通过MMU映射到物理地址空间中的实际位置。
  2. 进程空间

    进程空间(有时称为进程的虚拟地址空间)是指分配给单个进程的内存区域,它是进程可见的地址空间。每个进程都有自己的独立的虚拟地址空间,操作系统和MMU负责将此虚拟地址空间映射到物理地址空间上。这意味着两个不同的进程可以使用相同的虚拟地址指向不同的物理内存或者映射到相同的物理地址但是拥有不同的权限和属性。

地址空间和进程空间的关系

  • 隔离性:每个进程拥有独立的虚拟地址空间,这样即使它们的虚拟地址相同,也不会相互影响,因为这些地址映射到物理地址空间的不同部分。这提供了良好的安全性和稳定性,因为进程不能直接访问其他进程的内存。

  • 映射:操作系统的内存管理系统负责将进程的虚拟地址空间映射到物理地址空间。这通常通过页表完成,页表存储了虚拟地址到物理地址的映射信息。

  • 共享:尽管每个进程有自己独立的虚拟地址空间,但是有时候不同的进程需要共享内存。操作系统可以将同一块物理内存映射到多个进程的虚拟地址空间中,这通常用于进程间通信或共享库的映射。

因此,地址空间是处理器级别的内存寻址概念,而进程空间是操作系统级别的内存隔离和管理概念。操作系统通过虚拟内存管理技术,为每个进程创建了一种错觉,使其认为自己拥有连续的、独立的内存区域,而实际上它们是在共享同一个物理地址空间。

特性地址空间进程空间
定义CPU可以寻址的全部内存范围,包括物理和虚拟内存。分配给单个进程的虚拟内存区域,是进程可见和可操作的内存范围。
类型物理地址空间和虚拟地址空间。每个进程的虚拟地址空间。
用途CPU访问内存和其他资源的能力。隔离进程,确保进程内存访问的独立性和安全性。
管理由CPU和MMU负责物理和虚拟地址的映射。由操作系统负责管理,确保每个进程有独立的地址空间。
隔离性无(物理地址空间是共享的)。高(每个进程的虚拟地址空间彼此隔离)。
共享物理内存可以被多个进程共享(如通过共享内存)。虚拟地址空间通常是独立的,但可以有映射到相同物理内存的部分。
映射关系虚拟地址空间到物理地址空间的映射由页表或段表管理。进程的虚拟地址空间到物理地址空间的映射通过操作系统的内存管理器控制。
大小取决于CPU架构(32位、64位等)。取决于操作系统和系统配置,但通常每个进程的虚拟空间都有一个上限。
多样性通常一个系统中物理和虚拟地址空间是统一的。每个进程的进程空间可以不同,取决于其内存需求和操作系统的分配。

8.补充笔记:一个CPU有几个基址寄存器和界限寄存器?一个CPU有几个地址空间和进程空间?一个CPU有几个MMU?

CPU的基址寄存器和界限寄存器的数量,地址空间和进程空间的数量,以及MMU(内存管理单元)的数量,这些都不是固定的,而是取决于具体的CPU设计和它的用途。

  1. 基址寄存器和界限寄存器
    基址寄存器和界限寄存器主要用于分段内存管理。在分段内存管理系统中,每个段(segment)通过一对基址(base)和界限(limit)寄存器来描述。这样的寄存器对的数量取决于CPU的架构和设计。例如,较旧的x86架构的处理器可能只有几个用于分段的基址和界限寄存器(如CS, DS, ES, FS, GS, SS等),而更现代或者专用的处理器可能有更多或根本不使用分段内存管理。

  2. 地址空间和进程空间
    一个CPU通常管理一个地址空间,即它可以通过其地址线访问的全部内存范围。但这个地址空间可以通过不同的机制(如分页或分段)被映射到多个进程空间。每个进程空间可以想象成一个独立的地址空间,它是操作系统通过虚拟内存管理功能提供给单个进程的内存视图。理论上,一个操作系统可以支持任意多个进程空间,但实际上这受限于系统的物理内存、虚拟内存限制和操作系统设计。

  3. MMU(内存管理单元)
    大多数现代CPU会有一个内存管理单元(MMU)。MMU负责虚拟地址到物理地址的转换,并且通常支持分页或分段机制。一般情况下,每个CPU核心会有一个MMU。在多核心处理器中,每个核心可能有自己的MMU,或者有些设计可能共享一个MMU。

在讨论具体的CPU时,需要参考该CPU的技术手册或架构文档来获取准确的寄存器和硬件特性信息。

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

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

相关文章

Unix中的进程和线程-1

目录 1.如何创建一个进程 2.如何终止进程 2.2遗言函数 3.进程资源的回收 4.孤儿进程和僵尸进程 孤儿进程 (Orphan Process)&#xff1a; 僵尸进程 (Zombie Process)&#xff1a; 代码示例&#xff1a; 5. 进程映像的更新 在Linux中&#xff0c;进程和线程是操作系统进行工作调…

CAS 的 ABA 问题

一、什么是 ABA 问题 ABA 的问题: 假设存在两个线程 t1 和 t2. 有⼀个共享变量 num, 初始值为 A. 接下来, 线程 t1 想使⽤ CAS 把 num 值改成 Z, 那么就需要 先读取 num 的值, 记录到 oldNum 变量中. 使⽤ CAS 判定当前 num 的值是否为 A, 如果为 A, 就修改成 Z. 但是, 在…

CaT论文翻译

CaT: Balanced Continual Graph Learning with Graph Condensation CaT&#xff1a;通过图压缩实现平衡的连续图学习 Abstract 持续图学习(CGL)的目的是通过以流方式输入图数据来持续更新图模型。由于模型在使用新数据进行训练时很容易忘记以前学到的知识&#xff0c;因此灾…

基于SSM的宠物医院信息管理系统

项目简介 主要功能包括首页、个人中心、用户管理、医学知识管理、科室信息管理、医生信息管理、订单信息管理等。 管理员模块:管理员登录进入宠物医院信息管理系统可以查看个人中心、用户管理、医生管理、医学知识管理、科室信息管理、医生信息管理、预约挂号管理、医嘱信息管理…

AtCoder Beginner Contest 342 A - D

A - Yay! 大意 给定字符串&#xff0c;其中有且仅有一个字符与其他不同&#xff0c;输出这个字符的下标&#xff08;从1开始&#xff09;。 思路 桶排序统计次数即可。 代码 #include<iostream> #include<vector> using namespace std; int main(){string s;…

【前端面试3+1】06继承方式及优缺点、缓存策略、url输入到渲染全过程、【二叉树中序遍历】

一、继承有哪些方式&#xff1f;以及优缺点 继承的方式包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承和组合式继承。 1.原型链继承&#xff1a; 实现方式&#xff1a;将子类的原型指向父类的实例来实现继承。优点&#xff1a;简单易懂&#xff0c;代码量少。…

如何制作伸缩侧边栏?

目录 一、html-body 二、CSS 三、JS 四、完整代码 五、效果展示 一、html-body 侧边栏的伸缩需要用户触发事件&#xff0c;这里使用button为例&#xff0c;用户点击按钮实现侧边栏的打开和关闭。 <body><!-- 按钮&#xff0c;可以用文字、图片等作为事件源&am…

十三.youyiku分析案例(数分)

目录 youyiku分析案例(数分) 大框操作 1.销售情况随着时间的变化 2.不同产品的销量 柱状图(bar)改颜色排序 seaborn库(柱) --排序 3.每个城市的人喜欢的购物方式 4-不同年龄段的购物方式 添加标签段及值 --创建新表 对标签分别计算 绘图分析 youyiku分析案例(数分…

session反序列化漏洞2——ctfshow web263

题目链接 https://ctf.show/challenges#web263-723 解题思路 进去先是一个登录框 目录扫描一下发现存在源码泄露 查看源码 index.php error_reporting(0);session_start();//超过5次禁止登陆if(isset($_SESSION[limit])){$_SESSION[limti]>5?die("登陆失败次数超…

智过网:中级安全工程师一年能挣多少钱?工资高吗?

中级安全工程师的年收入是广大从业者非常关心的问题。毕竟&#xff0c;了解自己所处行业的薪资水平&#xff0c;不仅有助于规划个人职业发展&#xff0c;还能为日常生活中的决策提供重要参考。那么&#xff0c;中级安全工程师一年究竟能挣多少钱呢&#xff1f;工资又是否算高呢…

[leetcode] 100. 相同的树

给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出&#xff1a;true示例 2&a…

YOLOV5训练自己的数据集教程(万字整理,实现0-1)

文章目录 一、YOLOV5下载地址 二、版本及配置说明 三、初步测试 四、制作自己的数据集及转txt格式 1、数据集要求 2、下载labelme 3、安装依赖库 4、labelme操作 五、.json转txt、.xml转txt 六、修改配置文件 1、coco128.yaml->ddjc_parameter.yaml 2、yolov5x.…

第1章.提示词:开启AI智慧之门的钥匙

什么是提示词&#xff1f; 提示词&#xff0c;是引导语言模型的指令&#xff0c;让用户能够驾驭模型的输出&#xff0c;确保生成的文本符合需求。 ChatGPT&#xff0c;这位文字界的艺术大师&#xff0c;以transformer架构为基石&#xff0c;能轻松驾驭海量数据&#xff0c;编织…

嵌入式第一部分-第一集:ARM那些你得知道的事

ARM&#xff1a;Advanced RISC Machine&#xff0c;先进精简指令集机器 ARM公司只做设计&#xff0c;不生产。 国内IC生产厂商&#xff1a;华为海思、全志、瑞芯微、MTK&#xff08;联发科&#xff09; 扩展&#xff1a;ARM的商业模式了解。 使用三星S5PV210开发板进行视频的讲…

大数据 - Hadoop系列《五》- HDFS文件块大小及小文件问题

系列文章&#xff1a; 大数据- Hadoop入门-CSDN博客 大数据 - Hadoop系列《二》- Hadoop组成-CSDN博客 大数据 - Hadoop系列《三》- HDFS&#xff08;分布式文件系统&#xff09;概述_大量小文件的存储使用什么分布式文件系统-CSDN博客 大数据 - Hadoop系列《三》- MapRedu…

LeetCode算法——数组/字符串篇

对刷过的算法进行总结&#xff0c;所用解法都是最符合我个人逻辑的&#xff0c;以后再刷的话就看这篇帖子了 # 代码随想录——数组理论基础 首先要知道数组在内存中的存储方式&#xff0c;这样才能真正理解数组相关的面试题 数组是存放在连续内存空间上的相同类型数据的集合 …

IntelliJ IDEA 2023 for Mac 好用的Java开发工具

IntelliJ IDEA 2023是一款由JetBrains开发的强大的集成开发环境&#xff08;IDE&#xff09;软件&#xff0c;适用于多个编程语言。它旨在提高开发人员的生产力和代码质量&#xff0c;具有以下多种特色功能&#xff1a; 软件下载&#xff1a;IntelliJ IDEA 2023 v2023.3.6中文激…

2d导入人物素材进行分割后设置图层

1、设置分辨率大小 2、相机调整大小&#xff0c;要符合场景 3、选择2D sprite 编辑器 或者 点击这个也行 4、分割图像 5、设置过滤模式 6、图层设置

CAJViewer8.1下载地址及安装教程

CAJViewer是中国学术期刊&#xff08;CAJ&#xff09;全文数据库的专用阅读软件。CAJViewer是中国知识资源总库&#xff08;CNKI&#xff09;开发的一款软件&#xff0c;旨在方便用户在线阅读和下载CAJ数据库中的学术论文、期刊和会议论文等文献资源。 CAJViewer具有直观的界面…

Modbus协议介绍

Modbus存储区 从机存储数据&#xff0c;那么肯定要有一个存储区&#xff0c;那就需要文件操作&#xff0c;我们都知道这文件可以分为只读(-r)和读写(-wr)两种类型 并且存储的数据类型可以分为 &#xff1a;布尔量 和 16位寄存器 布尔量比如IO口的电平高低&#xff0c;灯的开关…