linux之进程地址空间
文章目录
- 1.进程地址空间回顾
- 1.1进程地址空间划分
- 1.2验证进程地址空间划分
- 1.简单划分
- 2.完整划分
- 2.初探进程地址空间
- 2.1初看现象
- 2.2Makefile的简便写法
- 3.进程地址空间详解
- 3.1地址空间是什么?
- 3.2地址空间的设计/由来
- 3.3空间区域划分
- 3.4如何理解地址空间?
- 3.5解释3.2的🐂🐎现象和fork()函数的返回值
- 3.6linux命令行的指令
- 4.可执行程序运行的底层
- 4.1linux下查看反汇编
- 4.2了解底层
- 5.为什么要大费周折设计地址空间?
- 5.1[地址空间+页表]对进程的非法访问进行有效拦截==>有效地保护了物理内存
- 5.2将内存管理模块和进程管理模块解耦合 提升内存利用率
- 5.35地址空间和页表实现了进程的独立性
- 6.对挂起状态的理解
- 6.1上篇博客的初识
- 6.2通过程序运行理解挂起状态
1.进程地址空间回顾
1.1进程地址空间划分

1.2验证进程地址空间划分
1.简单划分


- 一个C/C++程序 编译后形成的可执行程序 是一个二进制文件 在Linux下
./test是程序运行之后打印的 本质理解: 程序运行后执行的cout/printf实际上是进程在输出数据 - 堆和栈相对而生
2.完整划分
对程序的理解
1. int a = 10;
把字面常量10放到局部变量a
2. 单纯的字面常量放在代码李可以编译通过如:
"hello linux";
100;
'a';
验证程序地址空间划分


在堆区申请了一块空间 1. 释放时为什么只用将空间首地址传给free() 2. 差值为什么多了10个?
堆区申请x个字节 实际上c标准库给当前程序申请的比x多 多出来的空间 用来存储此次申请的属性信息 称作"Cokkie" 饼干数据 用来记录 什么时间申请的 申请的空间多大 等 上图中堆区数据字节差值为20也验证了这句话
总结:
- 32位下,一个进程的地址空间,取值范围是0x0000 0000 ~ 0xFFFF FFFF
[0,3GB]: 用户空间
[3GB,4GB]:内核空间 - 上面的结论,默认只在linux有效 [在windows下会跑出不一样的结果 windows注重地址安全 增加了一些自己的设计
2.初探进程地址空间
2.1初看现象
来看一个比较牛马的场景
#include <stdio.h>
#include <unistd.h>int g_val = 100;int main()
{pid_t id = fork();if(id == 0){int cnt = 0;//childwhile(1){printf("I am child, pid: %d, ppid: %d, g_val: %d, &g_val: %p\n",\getpid(), getppid(), g_val, &g_val);sleep(1);cnt++;if(cnt == 5){g_val = 200;printf(" child chage g_val 100 -> 200 success\n");}}}else {//fatherwhile(1){printf("I am father, pid: %d, ppid: %d, g_val: %d, &g_val: %p\n",\getpid(), getppid(), g_val, &g_val);sleep(1);}}
}
同时访问同一个地址出现了不同的值[在3.5解释]

由此得出结论 这里的地址绝对不是物理内存的地址!那他是什么🐂🐎?
- 这个🐂🐎是是虚拟地址/线性地址
- 之前学到的编程语言中的
"地址"概念不是物理地址而是虚拟地址 - OS不让用户直接访问物理地址 — 新手上路会犯错破坏内存 通过虚拟地址来保护
拓展知识
磁盘/网卡/显卡等外设也有寄存器 外设保存数据的寄存器可以称为端口/串口[硬件级别]

了解虚拟地址

逻辑地址

线性地址


2.2Makefile的简便写法
Makefile格式: target : prerequisties 目标文件: 先决条件
hello:hello.c hello.c1 hello.c2gcc -o $@ $^
$@: 依赖方法对应的依赖关系中的目标文件即hello
$^: 所有的依赖文件 即hello.c hello.c1 hello.c2这一堆文件
$< 第一个依赖文件 即hello.c
$? 比目标还要新的依赖文件列表
3.进程地址空间详解
3.1地址空间是什么?



富翁有10亿 底下有三个私生子 三个私生子互不知道对方的存在 富翁对他们三人分别承诺 他死后10亿就是他的 三人分别相信了 在富翁还存活时 三人找他要钱用 富翁也会给 但是如果要得太多 比如一次要了一亿 富翁就不给了 因为没有正当用途等原因
富翁 – OS 私生子 – 进程 老爹画的饼 – 地址空间
要注意的是:
内核中的地址空间 当未来和某一进程联系起来时 它实际上也是一种数据结构 因为他要对进程进行描述组织 即 富翁/OS 要对他画的饼/地址空间 进行组织 否则饼/进程太多了可能会露馅
3.2地址空间的设计/由来
我们首先要了解 计算机早期的设计是直接访问物理内存的 后来才引入了 线性地址/虚拟地址 显而易见引入虚拟地址是为了让计算机更好的工作 无论是安全问题或者是效率问题 看下面这种情况 就可以了解直接访问物理内存是极其危险的!

- 假设进程1中有一个野指针
int* p = 乱码进程1要对指针p进行访问/修改/删除操作 而这个指针恰好指向了进程2/3所在的内存 那么此时就芭比Q了[内存本身可以随时被读写] - 进程2是一个合法的正在运行的程序 一个hacker自己写了一个程序 在物理内存上运行 若此时进程2执行了让用户输入密码的操作 那么进程1可以通过在进程2中的相同地址处设一个指针接收 此时 hacker就获得了密码 这不彻底完蛋
- 进程1/2/3并不是一个个紧挨着的 此时就会有内存碎片问题 假设现在进程4来了 但是没有足够的地方 而实际上所有的碎片加起来是有地方的 那么OS就不得不把进程1/2/3再一个个挨着放 — 效率低下
上述这些问题的原因: 直接访问的是物理内存 对应的就是物理地址 现代计算机怎么设计的呢?
- 通过某种映射机制不直接访问物理内存
- 当虚拟地址是一个非法地址 禁止映射去访问物理内存
3.3空间区域划分

源码

3.4如何理解地址空间?
地址空间是一种内核数据结构 它里面要有各个区域的划分

- 每一个进程的页表映射的是物理内存的不同区域 这样保证了进程之间不相互干扰 保证进程之间的独立性
- 每一个进程都有自己的地址空间和页表
3.5解释3.2的🐂🐎现象和fork()函数的返回值


- 子进程的PCB大部分和父进程相同 少部分自己修改独有 val在父子进程的虚拟地址相同 映射机制相同
- 父子进程中的变量的虚拟地址相同 如果不发生拷贝 子进程的变量和父进程的变量在物理内存中是同一块空间
- 如果发生拷贝 此时在内存中当场为val开辟一块内存 用来存子进程新的值 这个过程叫写时拷贝 写时拷贝的优势在于 如果不发生拷贝 既符合虚拟地址的设计又不浪费空间
- 这就是为什么相同的地址(虚拟地址)有不同的值(不同的物理地址对应的不同值)
- 地址相同: 打印的地址是虚拟地址 值不同: 映射机制被改 子进程的值指向了自己的变量空间
解释之前讲的fork()函数一个返回值同时保存两个不同的值的问题

pid_t fork()
{//创建子进程return id;
}
pid_t Id = fork();
- 在
return id;之前 子进程已经被创建出来 父子进程分别return 自己代码的id值 return id;在fork()函数即将返回 执行return语句时 对Id值进行修改/写入 ===> 发生写时拷贝- 父子进程在物理内存中有各自的属于自己的变量空间 在用户层用同一个变量/虚拟地址来标识
3.6linux命令行的指令
readelf的用法
readelf是一个Linux下的命令行工具,用于查看ELF格式的目标文件或可执行文件的信息。ELF(Executable and Linkable Format)是一种常见的二进制文件格式,用于在Linux系统中表示可执行文件、共享库、目标文件等。使用readelf命令可以查看这些文件的头部、节区、符号表、重定位表等信息。以下是readelf命令的一些常用选项和用法:
- 查看目标文件的头部信息:
readelf -h <file>
- 查看目标文件的节区信息:
readelf -S <file>
- 查看目标文件的符号表信息:
readelf -s <file>
- 查看目标文件的重定位表信息:
readelf -r <file>
- 查看目标文件的动态符号表信息:
readelf -d <file>
- 查看目标文件的字符串表信息:
readelf -p <section_name> <file>
例如,要查看可执行文件ls的头部信息,可以使用以下命令:
readelf -h /bin/ls
objdump的用法
objdump是一个二进制文件反汇编工具,可以用于查看二进制文件的汇编代码、符号表、重定位表等信息。在Linux下,可以使用objdump命令来进行反汇编操作。以下是一些常用的objdump命令:
- 查看二进制文件的汇编代码
objdump -d <binary_file>
其中,-d表示反汇编操作,<binary_file>表示要反汇编的二进制文件。
- 查看二进制文件的符号表
objdump -t <binary_file>
其中,-t表示查看符号表。
- 查看二进制文件的重定位表
objdump -r <binary_file>
其中,-r表示查看重定位表。
- 查看二进制文件的头部信息
objdump -x <binary_file>
其中,-x表示查看头部信息。


objdump是一个二进制文件分析工具,可以用来查看二进制文件的汇编代码、符号表、重定位表等信息。-a选项表示显示所有信息,-f选项表示显示文件头信息,-h选项表示显示节头信息。
在Linux中,可以使用以下命令来查看二进制文件的所有信息:
objdump -afh <filename>
其中,<filename>是要查看的二进制文件的文件名。执行该命令后,会输出该二进制文件的所有信息,包括文件头信息、节头信息、符号表、重定位表等。
举个例子,如果要查看可执行文件/bin/ls的所有信息,可以执行以下命令:
objdump -afh /bin/ls
4.可执行程序运行的底层
4.1linux下查看反汇编
程序编译形成可执行程序 没有加载到内存时 在程序内部实际上已经有地址 – 可执行程序编译时内部已经有地址


4.2了解底层
- 地址空间不仅OS内部遵守,编译器也要遵守!
- 编译器编译代码的时候,已经形成了各个区域: 代码区,数据区 堆区 栈区…
- 采用和Linux内核中一样的编址方式,给每一个变量,每一行代码都进行了编址
- 程序在编译的时候,每一个字段(所有的代码和数据)早已经具有了一个虚拟地址
- 当可执行程序加载到内存时 每行代码/变量/函数便具有了一个外部物理地址
- CPU读取每一条执行时 指令内部也有地址 这个地址是虚拟地址
- 每一个变量/函数 都有一个编译器给出的虚拟地址 虚拟地址连同代码加载到了内存中

- 可执行程序运行 进入main函数 在虚拟地址(mm_struct)将0x0010到0x0019作为栈的start和end 变量a的虚拟地址为0x0010 其他亦然 将虚拟地址放在页表左侧 根据映射机制 映射一个物理地址作为变量a在物理内存的位置 物理地址放在页表右侧
- 假设访问完函数A后访问函数B 根据函数A的虚拟地址访问物理内存上的函数A 获取函数B的虚拟地址 按照虚拟地址查找页表 获取函数B的物理地址 (页表底层和哈希表相似
- 程序在编译的链接阶段链接动态库实际上是在代码中拷贝了库函数/调用接口的地址 依据地址去访问
- 这样CPU每次拿到的都是虚拟地址
- 地址空间: OS为进程设计的一种看待内存/外设的一种方案
5.为什么要大费周折设计地址空间?
5.1[地址空间+页表]对进程的非法访问进行有效拦截==>有效地保护了物理内存
- 对于非法的访问或映射 OS会识别并终止此进程 [代码运行后成为进程 由于代码写的不对 进程崩溃 即进程退出 实际上是OS杀死了这个不正确/不合法的进程]
- 地址空间和页表是OS创建并维护的 想使用地址空间和页表进行映射 要在OS的监管之下来进行访问
- 保护了物理内存中的所有的合法数据(各个进程,内核相关有效数据)
什么叫非法的访问/映射?
int main()
{char* str = "hello linux!\n";*str = 'H';
明显上述代码会报错 str存在于栈上 字符串存在只读常量区 不可修改 页表不仅会把虚拟地址映射为物理地址 还会有权限的检查 如果不具有写的权限 就终止 内存可以随时任意读写 地址空间和页表的存在使得它不在可以那么随意了!
5.2将内存管理模块和进程管理模块解耦合 提升内存利用率

地址空间 + 页表的映射 使得在物理内存中可以对未来加入内存的数据进行任意位置的加载(前提是有空间) 使得物理内存分配就和进程管理的工作分离 即内存管理模块和进程管理模块完成了解耦合
C/C++语言中父进程malloc/new空间时,本质是在虛拟地址空间申请的 优势:
-
代码写完形成可执行程序 这个程序可能不是马上运行 如果在写代码或者形成可执行程序时就为其申请了空间 那么程序不运行它不用这个空间 别的程序也没法用 这是一种极大的浪费 且 会造成效率大大降低
-
有地址空间的存在,上层申请空间是在地址空间上申请的,物理内存可以/甚至一个字节都不给(此时的申请的空间其实压根就不是空间只不过是编译器按照进程地址空间划分为每一句代码都生成了虚拟地址申请的空间也为他们生成了虚拟地址 当这个程序运行成为进程时通过映射才会真正的去物理内存申请空间)
-
当进行对物理地址空间访问的时候,才执行内存的相关管理算法缺页中断==>[操作系统自动完成用户和进程,完全0感知]然后在进行内存的访问


-
申请了物理空间,不立马使用是空间的浪费 通过延迟分配的策略来提高整机的效率 使得内存的有效使用几乎100%
5.35地址空间和页表实现了进程的独立性
- 理论上 物理内存可以对未来加入内存的数据进行任意位置的加载 那么实际上物理内存中的几乎所有数据和代码在内存中是乱序的
- 页表将地址空间上的虚拟地址和物理地址进行映射,在进程的视角下 内存分布是有序的 即地址空间+页表将内存的分布有序化
- 进程要访问的物理内存中的数据和代码,可能目前并没有在物理内存中,页表可以让不同的进程映射到不同的物理内存,即实现了进程独立性(不干扰其他进程+不知道有其他进程的存在)
- 地址空间的存在使得每一个进程都认为自己拥有 各个区域是有序的4GB空间(32位) ,不同的进程通过页表映射到不同的区域,实现了进程的独立性 每一个进程不知道也不需要知道其他进程的存在
6.对挂起状态的理解
6.1上篇博客的初识

6.2通过程序运行理解挂起状态
- 前面我们讲到
进程 = 进程内核数据结构(PCB) + 进程对应的磁盘上的可执行程序(代码+数据)现在我们了解到进程内核数据结构不仅仅有task_struct还有task_struct内的mm_struct* mm指针指向的mm_struct现在我们对进程的认识是进程 = 进程内核数据结构task_struct/mm_struct/页表 + 进程对应的磁盘上的可执行程序(代码+数据) - 程序是存放在磁盘上的,创建一个进程不是一开始就把所有的数据全部加载到内存里的,如果写了一百万行代码,程序大小4个G,结果运行的代码就几十行,把整个程序加载到内存中就是浪费内存
- 把代码和数据加载到内存本质就是创建进程 但是创建进程不是立马就把程序的所有代码和数据都加载到了内存中也不是立马创建内核数据结果建立映射关系 极端情况下 只有内核数据结构
task_struct/mm_struct被创建出来了 页表映射关系/代码和数据加载到内存 工作都没有完成 这个只创建了task_struct/mm_struct的状态叫新建状态当真正运行这个程序时 代码和数据才被加载到内存 - 理论上 可以实现对程序的分批加载 既然可以分批加载/换入(将磁盘上的代码和数据换入到内存) 那么也就可以分批换出 当这个进程短时间不会被执行如阻塞状态(需要等待某种资源: 网络 磁盘…) 这个进程的代码和数据 就可以被换出以节省空间让急于执行的/准备好的进程的代码和数据换入 被换出代码和数据的进程的状态叫挂起状态
相关文章:
linux之进程地址空间
文章目录 1.进程地址空间回顾1.1进程地址空间划分1.2验证进程地址空间划分1.简单划分2.完整划分 2.初探进程地址空间2.1初看现象2.2Makefile的简便写法 3.进程地址空间详解3.1地址空间是什么?3.2地址空间的设计/由来3.3空间区域划分3.4如何理解地址空间?3.5解释3.2的…...
Cloud微服务
当我们谈论“云微服务”时,通常是指基于云计算和微服务架构的应用程序开发和部署模型。以下是关于云微服务的一些详细信息: 微服务架构: 微服务架构是一种软件设计和开发模式,将应用程序划分为一组小型、独立的服务单元。每个服…...
BLIP-2:冻结现有视觉模型和大语言模型的预训练模型
Li J, Li D, Savarese S, et al. Blip-2: Bootstrapping language-image pre-training with frozen image encoders and large language models[J]. arXiv preprint arXiv:2301.12597, 2023. BLIP-2,是 BLIP 系列的第二篇,同样出自 Salesforce 公司&…...
PyQt(学习笔记)
学习资料来源: PyQt快速入门——b站王铭东老师 PyQt官网的所有模块 C具体实现的官方文档 PyQt(学习笔记) PyCharm环境准备运行第一个程序QPushButtonQLabelQLineEdit调整窗口大小、位置、图标布局信号与槽PyQt引入多线程 PyCharm环境准备 新…...
策略模式应用(内窥镜项目播放不同种类的视频)
新旧代码对比 策略模式 基本概念 策略模式是一种行为设计模式,它定义了一系列算法,将每个算法封装起来,并且使它们可以互相替换。策略模式允许客户端选择算法的具体实现,而不必改变客户端的代码。这样,客户端代码就…...
【操作系统】Bochs安装和配置
Bochs是使用C编写的高度可移植开源IA-32(X86)PC模拟器,能在大多数流行的平台上运行。它包括模拟Intel x86 CPU、常见I/O设备和自定义BIOS。Bochs可以被编译以模拟许多不同的x86 CPU,从386早期到最新的x86-64英特尔和AMD处理器甚至…...
【Vue】Node.js的下载安装与配置
目录 一.下载安装 官网: 二.环境变量的配置 三.设置全局路径和缓存路径 四.配置淘宝镜像 五.查看配置 六.使用npm安装cnpm 一.下载安装 官网: https://nodejs.org/en/download 下载完之后,安装的时候一直点next即可,…...
C语言从入门到实战——数组和指针的强化练习题
数组和指针的强化练习题 前言1. sizeof和strlen的对比1.1 sizeof1.2 strlen1.3 sizeof和strlen的对⽐ 2. 数组和指针笔试题解析2.1 一维数组2.2 字符数组2.3 二维数组 3. 指针运算笔试题解析3.1 题目1:3.2 题目23.3 题目33.4 题目43.5 题目53.6 题目63.7 题目7 前言…...
经典滑动窗口试题(一)
📘北尘_:个人主页 🌎个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上,不忘来时的初心 文章目录 一、将x减到0的最小操作数1、题目讲解2、讲解算法原理3、代码实现 二、无重复的最长子串1、题…...
【paddlepaddle】
安装paddlepaddle 报错 ImportError: /home/ubuntu/miniconda3/envs/paddle_gan/bin/../lib/libstdc.so.6: version GLIBCXX_3.4.30 not found (required by /home/ubuntu/miniconda3/envs/paddle_gan/lib/python3.8/site-packages/paddle/fluid/libpaddle.so) 替换 /home/ubu…...
String 、StringBuffer 和 StringBuilder 的区别?
String 使用 String 声明一个字符串的时候,该字符串会存放在堆中的字符串常量池中。因为在java中所有的String 都是以常量表示,且由 final 修饰,因此在线程池中它的线程是安全的 且 不可变的 。每个 String 在被创建后就不再发生任何变化。 …...
【DevOps】Git 图文详解(六):Git 利器 - 分支
Git 利器 - 分支 1.分支 Branch2.分支指令 🔥3.分支的切换 checkout4.合并 merge & 冲突4.1 🔸 快速合并(Fast forward)4.2 🔸 普通合并4.3 处理冲突 <<<<<<< HEAD 5.变基 rebase 分支是从主…...
万界星空科技QMS质量管理系统介绍
QMS(Quality Management System)质量管理系统是五大基础系统之一,在工业企业中被广泛的应用,在质量策划、生产过程质量监督、体系审核和文档管理等业务上发挥着不可替代的作用。 一般制造业工厂现状:质量成本高&#x…...
C练习题_14
一、单项选择题(本大题共 20小题,每小题 2分,共 40分。在每小题给出的四个备选项中,选出一个正确的答案,并将所选项前的字母填写在答题纸的相应位置上。) 以下叙述不正确的是() A.一个C源程序可…...
解决方案 | 政策与技术加持,法大大电子劳动合同让人事管理更省心
政策加持, 助力劳动合同电子化推广 近年来,国家人社部多次发文,明确电子劳动合同法律效力,鼓励推广电子劳动合同全面应用,积极引导、支持企业和劳动者依法规范订立电子劳动合同,优化人力资源社会保障公共服…...
Linux基础命令5
su——切换用户命令 例如,切换到stu用户底下 而切换到管理员的命令就是下图 切换完的区别就是 stu——root $——# 退出——exit 关机与重启命令 如果在右上角直接点x号,就相当于把电源拔断了,这样做的次数多了,有可能系统就…...
springboot(ssm中医学习服务管理系统 医学生在线学习平台Java(codeLW)
springboot(ssm中医学习服务管理系统 医学生在线学习平台Java(code&LW) 开发语言:Java 框架:ssm/springboot vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.7(或…...
springboot宠物领养系统-计算机毕设 附源码 44261
springboot宠物领养系统 摘 要 网络发布信息有其突出的优点,即信息量大,资源丰富,更新速度快等,很符合人们希望以捷、便利的方式获得最多最有效信息的要求。本系统就是一个网上宠物领养系统,为宠物爱好者提供一个信息…...
性能测试必备知识-使用MySQL存储过程构造大量数据:实例解析
在软件开发过程中,测试是一个不可或缺的环节。通过测试,我们可以发现并修复软件中的各种问题,提高软件的质量和稳定性。然而,手动编写大量的测试用例是一项耗时且容易出错的任务。为了解决这个问题,我们需要学会使用批…...
最新绿豆APP源码苹果CMS影视插件版本/原生JAVA源码+反编译开源+免授权
源码简介: 最新绿豆APP源码苹果CMS影视插件版本,它是原生JAVA源码反编译开源免授权,绿豆影视对接苹果CMS,它可以支持多功能自定义DIY页面布局。 1、新版绿豆视频APP视频6.1插件版反编译指南及教程 2、后端插件开源,可…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...


