当前位置: 首页 > news >正文

内存管理 I(内存管理的基本原理和要求、连续分配管理方式)

一、内存管理的基本原理和要求

内存管理(Memory Management)是操作系统设计中最重要和最复杂的内容之一。虽然计算机硬件技术一直在飞速发展,内存容量也在不断增大,但仍然不可能将所有用户进程和系统所需要的全部程序与数据放入主存,因此操作系统必须对内存空间进行合理的划分和有效的动态分配。操作系统对内存的划分和动态分配,就是内存管理的概念。

有效的内存管理在多道程序设计中非常重要,它不仅可以方便用户使用存储器、提高内存利用率,还可以通过虚拟技术从逻辑上扩充存储器。

内存管理的主要功能有:

在进行具体的内存管理之前,需要了解进程运行的基本原理和要求。

【总结】:

1. 内存的概念

内存可存放数据。程序执行前需要先放到内存中才能被 CPU 处理——缓和 CPU 与硬盘之间的速度矛盾。

2. 程序的链接与装入

创建进程首先要将程序和数据装入内存。将用户源程序变为可在内存中执行的程序,通常需要以下几个步骤:

  • 编译。由编译程序将用户源代码编译成若干目标模块(编译就是把高级语言翻译为机器语言)。
  • 链接。由链接程序将编译后形成的一组目标模块及它们所需的库函数链接在一起,形成一个完整的装入模块。
  • 装入(装载)。由装入程序将装入模块装入内存运行。

1)程序的链接

程序的链接有以下三种方式。

(a)静态链接

在程序运行之前,先将各目标模块及它们所需的库函数链接成一个完整的装配模块,以后不再拆开。将几个目标模块装配成一个装入模块时,需要解决两个问题:

  • ① 修改相对地址,编译后的所有目标模块都是从 0 开始的相对地址,当链接成一个装入模块时要修改相对地址。
  • ② 变换外部调用符号,将每个模块中所用的外部调用符号也都变换为相对地址。

(b)装入时动态链接

将用户源程序编译后所得到的一组目标模块,在装入内存时,采用边装入边链接的方式。其优点是便于修改和更新,便于实现对目标模块的共享。

(c)运行时动态链接

对某些目标模块的链接,是在程序执行中需要该目标模块时才进行的。凡在执行过程中未被用到的目标模块,都不会被调入内存和被链接到装入模块上。其优点是能加快程序的装入过程,还可节省大量的内存空间。

2)内存的装入

内存的装入模块在装入内存时,同样有以下三种方式:

(a)绝对装入

由于程序中的逻辑地址与实际内存地址完全相同,因此不需对程序和数据的地址进行修改。

(b)可重定位装入(静态重定位)

(c)动态运行时装入(动态重定位)

动态重定位的优点:可以将程序分配到不连续的存储区;在程序运行之前可以只装入部分代码即可投入运行,然后在程序运行期间, 根据需要动态申请分配内存;便于程序段的共享。

3. 逻辑地址与物理地址

编译后,每个目标模块都从 0 号单元开始编址,这称为该目标模块的相对地址(或逻辑地址)。当链接程序将各个模块链接成一个完整的可执行目标程序时,链接程序顺序依次按各个模块的相对地址构成统一的从 0 号单元开始编址的逻辑地址空间(或虚拟地址空间),对于 32 位系统,逻辑地址空间的范围为 0~232-1 。进程在运行时,看到和使用的地址都是逻辑地址。用户程序和程序员只需知道逻辑地址,而内存管理的具体机制则是完全透明的。不同进程可以有相同的逻辑地址,因为这些相同的逻辑地址可以映射到主存的不同位置。

物理地址空间是指内存中物理单元的集合,它是地址转换的最终地址,进程在运行时执行指令访问数据,最后都要通过物理地址从主存中存取。当装入程序将可执行代码装入内存时,必须通过地址转换将逻辑地址转换成物理地址,这个过程称为地址重定位

操作系统通过内存管理部件(MMU)将进程使用的逻辑地址转换为物理地址。进程使用虚拟内存空间中的地址,操作系统在相关硬件的协助下,将它 “转换” 成真正的物理地址。逻辑地址通过页表映射到物理内存,页表由操作系统维护并被处理器引用。

4. 进程的内存映像

不同于存放在硬盘上的可执行程序文件,当一个程序调入内存运行时,就构成了进程的内存映像。一个进程的内存映像一般有几个要素:

  • 代码段:即程序的二进制代码,代码段是只读的, 可以被多个进程共享。
  • 数据段:即程序运行时加工处理的对象,包括全局变量和静态变量。
  • 进程控制块(PCB):存放在系统区。操作系统通过 PCB 来控制和管理进程。
  • 堆:用来存放动态分配的变量。通过调用 malloc 函数动态地向高地址分配空间。
  • 栈:用来实现函数调用。从用户空间的最大地址往低地址方向增长。

代码段和数据段在程序调入内存时就指定了大小,而堆和栈不一样。当调用像 malloc 和 free 这样的 C 标准库函数时,堆可以在运行时动态地扩展和收缩。用户栈在程序运行期间也可以动态地扩展和收缩,每次调用一个函数,栈就会增长;从一个函数返回时,栈就会收缩。

5. 内存保护

确保每个进程都有一个单独的内存空间。内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。内存保护可采取两种方法:

1)在 CPU 中设置一对上、下限寄存器,存放用户作业在主存中的下限和上限地址,每当 CPU 要访问一个地址时,分别和两个寄存器的值相比,判断有无越界。

2)采用重定位寄存器(又称基地址寄存器)和界地址寄存器(又称限长寄存器)来实现这种保护。重定位寄存器含最小的物理地址值,界地址寄存器含逻辑地址的最大值。内存管理机构动态地将逻辑地址与界地址寄存器进行比较,若未发生地址越界,则加上重定位寄存器的值后映射成物理地址,再送交内存单元。

实现内存保护需要重定位寄存器和界地址寄存器,因此要注意两者的区别。重定位寄存器是用来 “加” 的,逻辑地址加上重定位寄存器中的值就能得到物理地址;界地址寄存器是用来 “比” 的,通过比较界地址寄存器中的值与逻辑地址的值来判断是否越界。

加载重定位寄存器和界地址寄存器时必须使用特权指令,只有操作系统内核才可以加载这两个存储器。这种方案允许操作系统内核修改这两个寄存器的值,而不允许用户程序修改。

6. 内存共享

并不是所有的进程内存空间都适合共享,只有那些只读的区域才可以共享。可重入代码又称纯代码,是一种允许多个进程同时访问但不允许被任何进程修改的代码。但在实际执行时,也可以为每个进程配以局部数据区,把在执行中可能改变的部分复制到该数据区,这样,程序在执行时只需对该私有数据区中的内存进行修改,并不去改变共享的代码。

下面通过一个例子来说明内存共享的实现方式:

考虑一个可以同时容纳 40 个用户的多用户系统,他们同时执行一个文本编辑程序,若该程序有 160KB 代码区和 40KB 数据区,则共需 8000KB 的内存空间来支持 40 个用户(即 (40KB + 160KB) × 40)。如果 160KB 代码是可分享的纯代码,则不论是在分页系统中还是在分段系统中,整个系统只需保留一份副本即可,此时所需的内存空间仅为 40KB × 40 + 160KB = 1760KB 。

  • 对于分页系统,假设页面大小为 4KB ,则代码区占用 40 个页面、数据区占用 10 个页面。为实现代码共享,应在每个进程的页表中都建立 40 个页表项,它们都指向共享代码区的物理页号。此外,每个进程还要为自己的数据区建立 10 个页表项,指向私有数据区的物理页号。

  • 对于分段系统,由于是以段为分配单位的,不管该段有多大,都只需为该段设置一个段表项(指向共享代码段始址,以及段长 160KB)。由此可见,段的共享非常简单易行。

此外,在进程与线程章节中我们介绍过基于共享内存的进程通信,由操作系统提供同步互斥工具。我们后续还将介绍一种内存共享的实现——内存映射文件。

7. 内存分配与回收

存储管理方式随着操作系统的发展而发展。在操作系统由单道向多道发展时,存储管理方式便由单一连续分配发展为固定分区分配。为了能更好地适应不同大小的程序要求,又从固定分区分配发展到动态分区分配。为了更好地提高内存的利用率,进而从连续分配方式发展到离散分配方式——页式存储管理。引入分段存储管理的目的,主要是为了满足用户在编程和使用方面的要求,其中某些要求是其他几种存储管理方式难以满足的。

二、连续分配管理方式

【总结】:

连续分配方式是指为一个用户程序分配一个连续的内存空间,譬如某用户需要 100MB 的内存空间,连续分配方式就在内存空间中为用户分配一块连续的 100MB 空间。连续分配方式主要包括单一连续分配、固定分区分配和动态分区分配。

1. 单一连续分配

2. 固定分区分配

下图是固定分区说明表和内存分配情况的示例图:

3. 动态分区分配

1)动态分区分配的基本原理

下图是动态分区分配的示例图:

【思考】:

(a)系统要用什么样的数据结构记录内存的使用情况?

(b)当很多个空闲分区都能满足需求时,应该选择哪个分区进行分配?

在动态分区分配中,与固定分区分配类似,设置一张空闲分区链(表),并按始址排序。分配内存时,检索空闲分区链,找到所需的分区,若其大小大于请求大小,便从该分区中按请求大小分割一块空间分配给装入进程(若剩余部分小到不足以划分,则无须分割),余下部分仍留在空闲分区链中。

(c)如何进行分区的回收操作?

回收内存时,系统根据回收分区的始址,从空闲分区链中找到相应的插入点,此时可能出现四种情况:

  • ① 回收区与插入点的后一空闲分区相邻,将这两个分区合并,并修改后一分区表项的始址和大小

  • ② 回收区与插入点的前一空闲分区相邻,将这两个分区合并, 并修改前一分区表项的大小为两者之和

  • ③ 回收区同时与插入点的前、后两个分区相邻,此时将这三个分区合并,修改前一分区表项的大小为三者之和,取消后一分区表项

  • ④ 回收区没有相邻的空闲分区,此时应为回收区新建一个表项,填写始址和大小,并插入空闲分区链

2)基于顺序搜索的分配算法

在进程 / 作业装入或换入主存时,若内存中有多个足够大的空闲块,则操作系统需要按照一定的分配算法从空闲分区链(表)中选出一个分区,以分配给该进程 / 作业使用,这就是动态分区的分配策略。按分区检索方式,可分为顺序分配算法和索引分配算法。

顺序分配算法是指依次搜索空闲分区链上的空闲分区,以寻找一个大小满足要求的分区,顺序分配算法有以下四种。

(a)首次适应(First Fit)算法

首次适应算法最简单,通常也是最好和最快的。不过,首次适应算法会使得内存的低地址部分出现很多小的空闲分区,而每次分配查找时都要经过这些分区,因此增加了开销。

(b)最佳适应(Best Fit)算法

最佳适应算法虽然称为 “最佳” ,但是性能通常很差,因为每次最佳的分配会留下很小的难以利用的内存块,会产生最多的外部碎片。

(c)最坏适应(Worst Fit)算法

最坏适应算法与最佳适应算法相反,它选择最大的可用块,这看起来最不容易产生碎片,但是却把最大的连续内存划分开,会很快导致没有可用的大内存块,因此性能也非常差。

(d)邻近适应(Next Fit)算法

邻近适应算法试图解决这个问题。但它常常导致在内存空间的尾部(因为在一遍扫描中,内存前面部分使用后再释放时,不会参与分配)分裂成小碎片。通常比首次适应算法要差。

【总结】:

算法算法思想分区排列顺序优点缺点
首次适应从头到尾找适合的分区空闲分区以地址递增次序排列综合看性能最好。算法开销小,回收分区后一般不需要对空闲分区队列重新排序/
最佳适应优先使用更小的分区,以保留更多大分区空闲分区以容量递增次序排列会有更多的大分区被保留下来,更能满足大进程需求会产生很多太小的、难以利用的碎片;算法开销大,回收分区后可能需要对空闲分区队列重新排序
最坏适应优先使用更大的分区,以防止产生太小的不可用的碎片空闲分区以容量递减次序排列可以减少难以利用的小碎片大分区容易被用完,不利于大进程;算法开销大,回收分区后可能需要对空闲分区队列重新排序
临近适应由首次适应演变而来,每次从上次查找结束位置开始查找空闲分区以地址递增次序排列(可排列成循环链表)不用每次都从低地址的小分区开始检索。算法开销小,回收分区后一般不需要对空闲分区队列重新排序会使高地址的大分区也被用完

3)基于索引搜索的分配算法

当系统很大时,空闲分区链可能很长,此时采用顺序分配算法可能很慢。因此,在大、中型系统中往往采用索引分配算法。

索引分配算法的思想是,根据其大小对空闲分区分类,对于每类(大小相同)空闲分区,单独设立一个空闲分区链,并设置一张索引表来管理这些空闲分区链。当为进程分配空间时,在索引表中查找所需空间大小对应的表项,并从中得到对应的空闲分区链的头指针,从而获得一个空闲分区。索引分配算法有以下三种。

(a)快速适应算法

空闲分区的分类根据进程常用的空间大小进行划分。分配过程分为两步:

  • ① 首先根据进程的长度,在索引表中找到能容纳它的最小空闲分区链表;
  • ② 然后从链表中取出第一块进行分配。

优点是查找效率高、不产生内部碎片;缺点是回收分区时,需要有效地合并分区,算法比较复杂,系统开销较大。

(b)伙伴系统

规定所有分区的大小均为 2 的 k 次幂(k 为正整数)。

当需要为进程分配大小为 n 的分区时(2i-1 < n ≤ 2i),在大小为 2i 的空闲分区链中查找。若找到,则将该空闲分区分配给进程。否则,表示大小为 2i 的空闲分区已耗尽,需要在大小为 2i+1 的空闲分区链中继续查找。

若存在大小为 2i+1 的空闲分区,则将其等分为两个分区,这两个分区称为一对伙伴,其中一个用于分配,而将另一个加入大小为 2i 的空闲分区链。若不存在,则继续查找,直至找到为止。回收时,也可能需要对伙伴分区进行合并。

(c)哈希算法

根据空闲分区链表的分布规律,建立哈希函数,构建一张以空闲分区大小为关键字的哈希表,每个表项记录一个对应空闲分区链的头指针。分配时,根据所需分区大小,通过哈希函数计算得到哈希表中的位置,从中得到相应的空闲分区链表。

4. 总结

以上三种内存分区管理方法(单一连续分配、固定分区分配、动态分区分配)有一个共同特点,即用户程序在主存中都是连续存放的。

在连续分配方式中,我们发现,即使内存有超过 1GB 的空闲空间,但若没有连续的 1GB 空间,则需要 1GB 空间的作业仍然是无法运行的;但若采用非连续分配方式,则作业所要求的 1GB 内存空间可以分散地分配在内存的各个区域,当然,这也需要额外的空间去存储它们(分散区域)的索引,使得非连续分配方式的存储密度低于连续分配方式。

非连续分配方式根据分区的大小是否固定,分为分页存储管理和分段存储管理。在分页存储管理中,又根据运行作业时是否要把作业的所有页面都装入内存才能运行,分为基本分页存储管理和请求分页存储管理。

三、小结

1、为什么要进行内存管理?

在单道系统阶段,一个系统在一个时间段内只执行一个程序,内存的分配极其简单,即仅分配给当前运行的进程。引入多道程序后,进程之间共享的不仅仅是处理机,还有主存储器。然而,共享主存会形成一些特殊的挑战。若不对内存进行管理,则容易导致内存数据的混乱,以至千影响进程的并发执行。因此,为了更好地支持多道程序并发执行,必须进行内存管理。

相关文章:

内存管理 I(内存管理的基本原理和要求、连续分配管理方式)

一、内存管理的基本原理和要求 内存管理&#xff08;Memory Management&#xff09;是操作系统设计中最重要和最复杂的内容之一。虽然计算机硬件技术一直在飞速发展&#xff0c;内存容量也在不断增大&#xff0c;但仍然不可能将所有用户进程和系统所需要的全部程序与数据放入主…...

【Redis】基于Redis实现秒杀功能

业务的流程大概就是&#xff0c;先判断优惠卷是否过期&#xff0c;然后判断是否有库存&#xff0c;最好进行扣减库存&#xff0c;加入全局唯一id&#xff0c;然后生成订单。 一、超卖问题 真是的场景下可能会有超卖问题&#xff0c;比如开200个线程进行抢购&#xff0c;抢100个…...

Hadoop 使用过程中 15 个常见问题的详细描述、解决方案

目录 问题 1&#xff1a;配置文件路径错误问题描述解决方案Python 实现 问题 2&#xff1a;YARN 资源配置不足问题描述解决方案Python 实现 问题 3&#xff1a;DataNode 无法启动问题描述解决方案Python 实现 问题 4&#xff1a;NameNode 格式化失败问题描述解决方案Python 实现…...

【Flutter 问题系列第 84 篇】如何清除指定网络图片的缓存

这是【Flutter 问题系列第 84 篇】&#xff0c;如果觉得有用的话&#xff0c;欢迎关注专栏。 博文当前所用 Flutter SDK&#xff1a;3.24.3、Dart SDK&#xff1a;3.5.3&#xff0c;网络图片缓存用的插件 cached_network_image: 3.4.1&#xff0c;缓存的网络图像的存储和检索用…...

【UE5】使用基元数据对材质传参,从而避免新建材质实例

在项目中&#xff0c;经常会遇到这样的需求&#xff1a;多个模型&#xff08;例如 100 个&#xff09;使用相同的材质&#xff0c;但每个模型需要不同的参数设置&#xff0c;比如不同的颜色或随机种子等。 在这种情况下&#xff0c;创建 100 个实例材质不是最佳选择。正确的做…...

鸿蒙动画开发07——粒子动画

1、概 述 粒子动画是在一定范围内随机生成的大量粒子产生运动而组成的动画。 动画元素是一个个粒子&#xff0c;这些粒子可以是圆点、图片。我们可以通过对粒子在颜色、透明度、大小、速度、加速度、自旋角度等维度变化做动画&#xff0c;来营造一种氛围感&#xff0c;比如下…...

IDEA2023 创建SpringBoot项目(一)

一、Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。 二、快速开发 1.打开IDEA选择 File->New->Project 2、…...

VSCode:终端打开一片空白,无cmd

第一步&#xff1a;找到右下角设置图标 第二步&#xff1a;找到 Terminal - Integrated - Default Profile: Windows: 选择一个本地存在的命令方式&#xff0c;重启即可 也可以直接在右下角直接选择...

Zea maize GO

1.涉及到新旧基因组的转化 B73v4_to_B73v5 &#xff08;davidbioinformatics只支持新版基因组&#xff09; MaizeGDB Map文件下载https://download.maizegdb.org/Pan-genes/B73_gene_xref/小处理脚本&#xff08;制作map文件&#xff09; import pandas as pd# 读取CSV文件 …...

Android开发实战班 - 数据持久化 - 数据加密与安全

在 Android 应用开发中&#xff0c;数据安全至关重要&#xff0c;尤其是在处理敏感信息&#xff08;如用户密码、支付信息、个人隐私数据等&#xff09;时。数据加密是保护数据安全的重要手段&#xff0c;可以有效防止数据泄露、篡改和未经授权的访问。本章节将介绍 Android 开…...

EDA实验设计-led灯管动态显示;VHDL;Quartus编程

EDA实验设计-led灯管动态显示&#xff1b;VHDL&#xff1b;Quartus编程 引脚配置实现代码RTL引脚展示现象记录效果展示 引脚配置 #------------------GLOBAL--------------------# set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED" set_…...

Eclipse 查找功能深度解析

Eclipse 查找功能深度解析 Eclipse 是一款广受欢迎的集成开发环境(IDE),它为各种编程语言提供了强大的开发工具。在本文中,我们将深入探讨 Eclipse 的查找功能,这是开发者日常工作中不可或缺的一部分。无论是查找代码中的特定字符串,还是进行更复杂的搜索,如正则表达式…...

第三百二十九节 Java网络教程 - Java网络UDP套接字

Java网络教程 - Java网络UDP套接字 TCP套接字是面向连接的&#xff0c;基于流。基于UDP的套接字是无连接的&#xff0c;基于数据报。 使用UDP发送的数据块称为数据报或UDP数据包。每个UDP分组具有数据&#xff0c;目的地IP地址和目的地端口号。 无连接套接字在通信之前不建立…...

Leetcode215. 数组中的第K个最大元素(HOT100)

链接 第一次&#xff1a; class Solution { public:int findKthLargest(vector<int>& nums, int k) {sort(nums.begin(),nums.end());int n nums.size();return nums[n-k];} }; 这显然不能出现在面试中&#xff0c;因为面试官考察的不是这个。 正确的代码&#…...

QT与嵌入式——搭建串口

1、源码 由于我需要不止一个串口来进行数据交互&#xff0c;所以简单的封装了一下 void Usb_Init(QString portName, QSerialPort *Port) {Port->setPortName(portName);Port->setBaudRate(QSerialPort::Baud115200); // 设置波特率&#xff0c;根据你的开发板配置修改…...

Shell编程-6

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;shell(6)if条件判断与for循环结构_哔哩哔哩_bilibili 一、if条件判断 在Shell脚本中&#xff0c;if语句用于基于条件的评估来执行不同的代码块。…...

使用 Postman 设置 Bearer Token 进行身份验证

学习笔记 1. 打开 Postman 并创建新请求 打开 Postman。 在左上角点击 按钮&#xff0c;创建一个新的请求。 2. 选择 HTTP 方法 在请求类型&#xff08;默认为 GET&#xff09;旁边的下拉菜单中&#xff0c;选择你需要的 HTTP 方法&#xff0c;如 POST、GET、PUT 等。 3…...

现在转前端怎么样?

互联网技术日新月异&#xff0c;软件开发者追逐技术浪潮的脚步从未停歇。在这个快速发展的行业中&#xff0c;如何规划自己的职业道路&#xff0c;选择合适的技术方向&#xff0c;成为了许多开发者面临的重要抉择。本文将围绕技术选择这个话题&#xff0c;分享一些深入的思考和…...

【算法一周目】滑动窗口(1)

目录 长度最小的子数组 解题思路 代码实现 无重复字符的最大字串 解题思路 代码实现 最大连续1的个数l l l 解题思路 代码实现 将x减到0的最小操作数 解题思路 代码实现 长度最小的子数组 题目链接&#xff1a;209. 长度最小的子数组题目描述&#xff1a; 给定一个…...

React Native 基础

React 的核心概念 定义函数式组件 import组件 要定义一个Cat组件,第一步要使用 import 语句来引入React以及React Native的 Text 组件: import React from react; import { Text } from react-native; 定义函数作为组件 const CatApp = () => {}; 渲染Text组件...

【C++笔记】list使用详解及模拟实现

前言 各位读者朋友们大家好&#xff01;上期我们讲了vector的使用以及底层的模拟实现&#xff0c;这期我们来讲list。 目录 前言一. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.…...

【机器学习】机器学习中用到的高等数学知识-7.信息论 (Information Theory)

熵 (Entropy)&#xff1a;用于评估信息的随机性&#xff0c;常用于决策树和聚类算法。交叉熵 (Cross-Entropy)&#xff1a;用于衡量两个概率分布之间的差异&#xff0c;在分类问题中常用。 信息论作为处理信息量和信息传输的数学理论&#xff0c;在机器学习中具有广泛的应用。…...

《现代制造技术与装备》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答 问&#xff1a;《现代制造技术与装备》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的第二批认定学术期刊。 问&#xff1a;《现代制造技术与装备》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a;齐鲁工业大学&#xff0…...

09 - Clickhouse的SQL操作

目录 1、Insert 1.1、标准 1.2、从表到表的插入 2、Update和Delete 2.1、删除操作 2.2、修改操作 3、查询操作 3.1、with rollup&#xff1a;从右至左去掉维度进行小计 3.2、with cube : 从右至左去掉维度进行小计&#xff0c;再从左至右去掉维度进行小计 3.3、with …...

如何解决pdf.js跨域从url动态加载pdf文档

摘要 当我们想用PDF.js从URL加载文档时&#xff0c;将会因遇到跨域问题而中断&#xff0c;且是因为会触发了PDF.js和浏览器的双重CORS block&#xff0c;这篇文章将会介绍&#xff1a;①如何禁用pdf.js的跨域&#xff1f;②如何绕过浏览器的CORS加载URL文件&#xff1f;②如何使…...

深入理解TTY体系:设备节点与驱动程序框架详解

往期内容 本专栏往期内容&#xff1a;Uart子系统 UART串口硬件介绍 interrupt子系统专栏&#xff1a; 专栏地址&#xff1a;interrupt子系统Linux 链式与层级中断控制器讲解&#xff1a;原理与驱动开发 – 末片&#xff0c;有专栏内容观看顺序 pinctrl和gpio子系统专栏&#xf…...

库的操作(MySQL)

1.创建数据库 语法&#xff1a; CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specification:[DEFAULT] CHARACTER SET charset_name[DEFAULT] COLLATE collation_name说明&#xff1a; 大写的表示关键字 [ ] 是可…...

在 for 循环中,JVM可能会将 arr.length 提升到循环外部,仅计算一次。可能会将如何解释 详解

在 Java 的 for 循环中&#xff0c;JVM 有能力进行优化&#xff0c;将 arr.length 的访问提升到循环外部&#xff0c;避免每次迭代都重新计算 arr.length。这种优化主要是由于 JVM 的 即时编译器&#xff08;JIT&#xff09; 和 逃逸分析&#xff08;Escape Analysis&#xff0…...

回溯--数据在内存中的存储:整数、大小端和浮点数的深度解析

目录 引言 1. 整数在内存中的存储 1.1 原码、反码和补码 1.2 为什么使用补码&#xff1f; 1.3 示例代码&#xff1a;整数的存储 2. 大小端字节序和字节序判断 2.1 什么是大端和小端&#xff1f; 2.2 为什么会有大端和小端之分&#xff1f; 2.3 字节序的判断小程序 2.…...

第二十二章 Spring之假如让你来写AOP——Target Object(目标对象)篇

Spring源码阅读目录 第一部分——IOC篇 第一章 Spring之最熟悉的陌生人——IOC 第二章 Spring之假如让你来写IOC容器——加载资源篇 第三章 Spring之假如让你来写IOC容器——解析配置文件篇 第四章 Spring之假如让你来写IOC容器——XML配置文件篇 第五章 Spring之假如让你来写…...

免展网站后台注册/微信小程序开发费用

很多小伙伴都表示&#xff1a;什么&#xff1f;用好Excel就可以做这年头最炫酷的人力资本分析师&#xff1f;这和我想象中的完全不一样啊&#xff01;怎么着……也得写写代码才够逼格吧&#xff1f;好的&#xff0c;今天就满足你们想要写代码的愿望。 图片来自网络&#xff0c;…...

企业网站pc优化/web3域名注册

本文实例讲述了Android编程之手机壁纸WallPaper设置方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;/*** Andorid设置手机屏幕的壁纸** description&#xff1a;* author ldm* date 2016-5-4 下午3:08:56*/public class SetWallpaperActivity extends Activity {/…...

可视方便建站微网站哪个好怎么用/站长之家seo工具包

规则: AssertFalse Boolean,boolean 验证注解的元素值是false AssertTrue Boolean,boolean 验证注解的元素值是true NotNull 任意类型 验证注解的元素值不是null Null 任意类型 验证注解的元素值是null BigDecimal, BigInteger, byte,short, int, long&#xff0c;等任何Number…...

做网站价位/电脑全自动挂机赚钱

几种并发服务器模型的实现&#xff1a;多线程&#xff0c;多进程&#xff0c;select&#xff0c;poll&#xff0c;epoll - rail 时间 2014-07-31 00:18:00 博客园-所有随笔区原文 http://www.cnblogs.com/wj9012/p/3879605.html主题 Socket 多线程 Epoll#include <stdio.h&…...

微网站和微信公共平台的区别/广告优化师的工作内容

Linux是什么&#xff1f;linux是一个开源操作系统&#xff0c;是用于与计算机硬件打交道的中间层。操作系统管理系统资源&#xff0c;提供最基本的计算功能&#xff0c;如管理及配置内存&#xff0c;同时还提供一些基本的服务程序&#xff0c;如&#xff1a;文件系统、设备驱动…...

只做美食类目产品的网站/整站优化seo

一、单项选择题 ( ) 1. 数据的四种基本逻辑结构是指。 A. 链表、数组、串、图状结构 B. 线性表、链表、栈队列、数组 C. 线性结构、链表、树形结构、图形结构 D. 集合、线性结构、树形结构、图状结构 ( ) 2 .评价算法的时间复杂性&#xff0c;比较“对数阶量级”与“…...