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

(linux操作系统)程序地址空间

程序地址空间是什么?

 

        讲这个问题之前,我们先来看一段熟悉的代码,以前学习C语言或者C++语言时,就听说过程序内存分布,堆区,栈区,静态区,常量区,共享区,代码段,初始化/未初始化全局变量区等概念

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_unval;
int g_val = 100;
int main(int argc, char *argv[], char *env[])
{const char *str = "helloworld";printf("code addr: %p\n", main);printf("init global addr: %p\n", &g_val);printf("uninit global addr: %p\n", &g_unval);static int test = 10;char *heap_mem = (char*)malloc(10);char *heap_mem1 = (char*)malloc(10);char *heap_mem2 = (char*)malloc(10);char *heap_mem3 = (char*)malloc(10);printf("heap addr: %p\n", heap_mem); //heap_mem(0), &heap_mem(1)printf("heap addr: %p\n", heap_mem1); //heap_mem(0), &heap_mem(1)printf("heap addr: %p\n", heap_mem2); //heap_mem(0), &heap_mem(1)printf("heap addr: %p\n", heap_mem3); //heap_mem(0), &heap_mem(1)printf("test static addr: %p\n", &test); //heap_mem(0), &heap_mem(1)printf("stack addr: %p\n", &heap_mem); //heap_mem(0), &heap_mem(1)printf("stack addr: %p\n", &heap_mem1); //heap_mem(0), &heap_mem(1)printf("stack addr: %p\n", &heap_mem2); //heap_mem(0), &heap_mem(1)printf("stack addr: %p\n", &heap_mem3); //heap_mem(0), &heap_mem(1)printf("read only string addr: %p\n", str);for(int i = 0 ;i < argc; i++){printf("argv[%d]: %p\n", i, argv[i]);}for(int i = 0; env[i]; i++){printf("env[%d]: %p\n", i, env[i]);}return 0;}

 

我们运行一下代码

        我们观察一下运行结果,发现,我们的程序在内存中的分布是非常有规律的,栈是向下增长的,堆区是向上增长的,栈的地址要大于堆的地址,堆区和栈区之间还有一块共享区,环境变量和命令行参数的地址是最大的,最小的地址是代码段,然后是常量区,其次是初始化未初始化全局变量。

就像下面的图片一样

我们发现这个程序在内存里面的分布的非常有规律,我们以32位操作系统来举例,内核空间占内存1G,剩下的3G被称为用户空间,这是因为32位操作系统最大能寻址4096MB的内存 这时后会有一

个疑问,那么一个程序在内存中的空间分布是这样的,那么如果有多个程序呢,如果都按照这样分布,不就有点不合理了吗,程序与程序直接的内存空间不会打架吗,接下来我们再看一个小实验

来看看下面的代码

# include<stdio.h>
# include<unistd.h>
# include<sys/types.h>int val = 5;
int main()
{pid_t id = fork();if(id == 0){printf("子进程创建pid == %d ppid = %d\n",getpid(),getppid());while(val){printf("子进程,val的地址: %p val的值== %d \n",&val,val);val--;}}else {printf("我是父进程 pid == %d ,val的地址%p \n",getpid(),&val );printf("父进程val的值 == %d",val);}return 0;
}

这里我们让子进程里面的val依次-- 并且打印地址,同时查看父进程val的值和地址 看看结果

这里我们发现子进程修改val的值和父进程val的值的地址居然一样!! 

我们要知道一个概念:

进程具有独立性:

  • 每一个进程的task_struct内核数据结构独立。
  • 内存中的代码和数据独立。

根据上面的概念,这显然是不合理的,这如果是物理地址肯定就说不过去,那么这是什么? 这是虚拟地址

下面我们直接说结论:

  • 一个进程一个虚拟地址空间
  • 一个进程一套页表

  根据上面的结论,再结合我们给的代码例子,我们再简单的谈谈页表和虚拟地址空间

页表是什么

  页表是操作系统维护的数据结构,他本质也是一个数据结构,用于记录虚拟地址到物理地址的映射关系。每个进程有独立的页表,简单的来讲页表就是虚拟地址映射到物理地址的一个工具,页表里面存放的是虚拟地址空间和物理地址空间。

有了这个概念之后,我们知道我们的程序地址空间是虚拟的,不是物理的,那么为什么我们上面举的例子他们子进程和父进程的虚拟地址还是一样的?

我们来画图说明一下

        这里的虚拟地址空间的位宽是1字节,那我们的int是4字节,那是如何处理的?我们有int这个类型,我们这里存放的地址其实是int四字节里面地址最小的那一个字节,在访问变量时,知道开始地址,再知道偏移量就行了。

当我们的子进程想要修改val的值时,我们的操作系统就会介入,(因为要保证进程的独立性) 拷贝一个val的值到新的物理内存中,再更改子进程对应的页表映射,映射到新的物理地址上面,供子进程使用,并且不影响到父进程,这就是写时拷贝!

        一个进程对应一个页表,一个虚拟地址空间

        所以我们打印出来的地址都是一样的了,那么为什么虚拟地址不用改呢,那是因为子进程和父进程的页表里面的内容互不冲突,只要保证自己页表里面的地址不冲突就行了,有了以上的映射关系之后,我们在物理内存里面就可以随便存放了

        我们用户是看不到物理内存的,物理内存由操作系统统一管理,所以我们在调试代码的时候看到的内存全是虚拟地址。

        页表的映射是由谁完成的,笼统的来说就是由操作系统完成的,本质上来说是由mmu的内存管理单元的一个硬件设备完成的

那么为什么要这样设计呢,我们下面来说说

怎么办?虚拟地址和程序地址空间

我们看看下面的图片

 每个进程会认为自己独占4G内存空间,进程之间是相互独立的,进程认为我得到的是物理地址,其实是操作系统分配的虚拟地址,而这些虚拟地址由操作系统统一管理,怎么管理?先描述再组织!而虚拟地址空间本质就是一个名为mm_struct的数据结构!!而这个mm_struct存放task_struct里面

而mm_struct就是描述一个程序地址空间的结构体!

那他是怎么描述的呢,其实很简单

我们举个例子:

我们要在一个桌子上面划分区域,这个桌子长一米

在mm_struct里面也是如此,就像下面这样

struct mm_struct
{
long code_start;
long code_end;
long init_data_start;
long init_data_end;
............}

而调整区域就做相应区域的+=,-=就可以了。只需要确认区域的开始和结束即可!每个进程都会有自己的mm_struct当进程少时就用链表这个数据结构来组织mm_struct,当mm_struct多时就用红黑树

我们来看看源码

struct mm_struct
{/*...*/struct vm_area_struct *mmap; /* 指向虚拟区间(VMA)链表 */ struct rb_root mm_rb; /* red_black树 */ unsigned long task_size; /*具有该结构体的进程的虚拟地址空间的⼤⼩*/ /*...*/// 代码段、数据段、堆栈段、参数段及环境段的起始和结束地址。 unsigned long start_code, end_code, start_data, end_data;unsigned long start_brk, brk, start_stack;unsigned long arg_start, arg_end, env_start, env_end;/*...*/}

这个vm_area_struct *mmap又是什么呢?

我们想一个问题,像栈区可以用++,--实现空间的改变,栈在虚拟内存中只存在一份,但是堆呢,堆肯定不止一份吧,那他又是怎么存储的呢,我们看看下面的图片

        这里的vm_area_struct也是一个结构体,他里面描述的是一块的空间,看上面的图片一个vm_area描述一个栈的空间,一个vm_area描述一个栈堆的空间,如果有两个堆在来一个vm_area描述,然后在把这个vm_area用一个数据结构组织起来,这样就解决了堆不止一个的问题,我们来看看源代码

struct vm_area_struct {
unsigned long vm_start; //虚存区起始
unsigned long vm_end; //虚存区结束
struct vm_area_struct *vm_next, *vm_prev; //前后指针
struct rb_node vm_rb; //红⿊树中的位置
unsigned long rb_subtree_gap;
struct mm_struct *vm_mm; //所属的 mm_struct
pgprot_t vm_page_prot;
unsigned long vm_flags; //标志位
struct {
struct rb_node rb;
unsigned long rb_subtree_last;
} shared;
struct list_head anon_vma_chain;
struct anon_vma *anon_vma;
const struct vm_operations_struct *vm_ops; //vma对应的实际操作
unsigned long vm_pgoff; //⽂件映射偏移量
struct file * vm_file; //映射的⽂件
void * vm_private_data; //私有数据
atomic_long_t swap_readahead_info;
#ifndef CONFIG_MMU
struct vm_region *vm_region; /* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
struct mempolicy *vm_policy; /* NUMA policy for the VMA */
#endif
struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;

这里在补充几点

 

        操作系统在加载进程时,先建立虚拟内存映射,再按需加载数据到物理内存(通过缺页中断机制)。这是现代操作系统(如Linux、Windows)的主流实现方式,目的是提高内存利用率和启动效率。

        缺页中断又是什么,缺页中断就是在页表里面,有我们的代码和数据的虚拟地址空间,但是在物理内存中没有,此时操作系统就会把对应的代码从硬盘上加载到物理内存中,补齐对应的页表映射关系。

为什么要这么设计

  • 将无序的内存,变成有序的,方便管理
  • 地址转换过程中,可以对访问的地址进行合法判断,防止不可恢复的错误发生

·       我们来想一个问题,我们定义的常量字符串,如果我们从代码上面修改,这个代码肯定是能编过的,但我们执行时,操作系统就会不让我们执行,就会崩溃,我们知道常量字符串是被编写到代码段的,代码段是不可被修改的,那么操作系统是怎么判断的呢,就是通过页表对应地址的权限来判断的,查找页表的时候,权限被拦截了!(页表出了物理虚拟内存的映射条目,还有权限条目)

  • 让进程管理和内存管理进行一定的解耦合

        为什么这么说,我们的进程和内存之间通过页表进行联系,这个结构就是一个高内聚低耦合的一个设计,进程与内存之间没有直接的关联,我们谈一谈进程挂起,我们知道我们进程被挂起了,代表内存不够用了,操作系统就会把对应代码和数据的内存释放掉,但保留这个进程的

        task_struct,这个task_struct里面就会有页表,页表里面对应的虚拟地址还在,但物理地址被操作系统给释放掉了,当下一次要调度这个进程时,就可以把对应的代码和数据重新建立映射关系,这样操作系统对内存的管理就和进程没什么太大的影响。所以让进程管理和内存管理进行一定的解耦合。

我们再说说野指针问题

当一个指针的指向的物理地址被释放了,对应页表的虚拟地址也要被释放,所以映射关系就要去掉,如果我们此时再操作指针去操作这个地址时,查找页表就会失败,失败就会可能导致进程崩溃,所以有了野指针之后,进程可能崩溃。

 

我们再总结一下

为什么要有虚拟地址空间

这个问题其实可以转化为:如果程序直接可以操作物理内存会造成什么问题? 在早期的计算机中,要运⾏⼀个程序,会把这些程序全都装⼊内存,程序都是直接运⾏在内存上的, 也就是说程序中访问的内存地址都是实际的物理内存地址。当计算机同时运⾏多个程序时,必须保证 这些程序⽤到的内存总量要⼩于计算机实际物理内存的⼤⼩。
那当程序同时运⾏多个程序时,操作系统是如何为这些程序分配内存的呢?例如某台计算机总的内存 ⼤⼩是128M,现在同时运⾏两个程序A和B,A需占⽤内存10M,B需占⽤内存110。计算机在给程序分 配内存时会采取这样的⽅法:先将内存中的前10M分配给程序A,接着再从内存中剩余的118M中划分 出110M分配给程序B。 这种分配⽅法可以保证程序A和程序B都能运⾏,但是这种简单的内存分配策略问题很多。
安全风险
每个进程都可以访问任意的内存空间,这也就意味着任意⼀个进程都能够去读写系关内
存区域,如果是⼀个⽊⻢病毒,那么他就能随意的修改内存空间,让设备直接瘫痪。
地址不确定
众所周知,编译完成后的程序是存放在硬盘上的,当运⾏的时候,需要将程序搬到内存当中 去运⾏,如果直接使⽤物理地址的话,我们⽆法确定内存现在使⽤到哪⾥了,也就是说拷贝 的实际内存地址每⼀次运⾏都是不确定的,⽐如:第⼀次执⾏a.out时候,内存当中⼀个进程 都没有运⾏,所以搬移到内存地址是0x00000000,但是第⼆次的时候,内存已经有10个进程 在运⾏了,那执⾏a.out的时候,内存地址就不⼀定了
效率低下
如果直接使⽤物理内存的话,⼀个进程就是作为⼀个整体(内存块)操作的,如果出现物理
内存不够⽤的时候,我们⼀般的办法是将不常⽤的进程拷贝到磁盘的交换分区中,好腾出内
存,但是如果是物理地址的话,就需要将整个进程⼀起拷⾛,这样,在内存和磁盘之间拷贝
时间太⻓,效率较低。
存在这么多问题,有了虚拟地址空间和分页机制就能解决了吗?当然!
地址空间和页表是OS创建并维护的!是不是也就意味着,凡是想使⽤地址空间和页表进⾏映射, 也⼀定要在OS的监管之下来进⾏访问!!也顺便 ,包括各个 进程以及内核的相关有效数据!
保护了物理内存中的所有的合法数据
因为有地址空间的存在和页表的映射的存在,我们的物理内存中可以对未来的数据进⾏任意位置 的加载!物理内存的分配 和 进程的管理就可以做到没有关系, 。
进程管理模块和内存管理模块就完
成了解耦合
因为有地址空间的存在,所以我们在C、C++语⾔上new, malloc空间的时候,其实是在地址 空间上申请的,物理内存可以甚⾄⼀个字节都不给你。⽽当你真正进⾏对物理地址空间访问 的时候,才执⾏内存的相关管理算法,帮你申请内存,构建页表映射关系(延迟分配),这 是由操作系统⾃动完成,⽤⼾包括进程完全0感知!!
因为页表的映射的存在,程序在物理内存中理论上就可以任意位置加载。它可以将地址空间上的
虚拟地址和物理地址进⾏映射,在 进程视角所有的内存分布都可以是有序 的。

 

 

 

 

相关文章:

(linux操作系统)程序地址空间

程序地址空间是什么&#xff1f; 讲这个问题之前&#xff0c;我们先来看一段熟悉的代码&#xff0c;以前学习C语言或者C语言时&#xff0c;就听说过程序内存分布&#xff0c;堆区&#xff0c;栈区&#xff0c;静态区&#xff0c;常量区&#xff0c;共享区&#xff0c;代码段&am…...

专业抑郁测试工具:让心理健康评估更简单

专业抑郁测试工具&#xff1a;让心理健康评估更简单 在这个快节奏的社会中&#xff0c;心理健康问题越来越受到人们的关注。为了帮助大家更好地了解自己的心理状态&#xff0c;我们开发了一款专业的在线抑郁测试工具。这个工具基于科学的心理量表设计&#xff0c;为用户提供准…...

C语言中单向链表:创建节点与插入新节点

一. 简介 单链表是一种常见且基础的数据结构&#xff0c;由一系列节点组成&#xff0c;每个节点包含数据和一个指向下一个节点的指针。 本文简单学习一下C语言中如何实现单项链表。 二. C语言实现单向链表 单向链表&#xff1a;单向链表是一种线性数据结构&#xff0c;由一…...

jsoncpp的使用

json提供的几个类&#xff1a; Value类&#xff1a;将json支持的数据类型进行包装&#xff0c;最终得到一个Value类型 FastWriter类&#xff1a;将Value对象中的数据序列化为字符串&#xff0c;序列化后可以得到json格式的字符串 Reader类&#xff1a;反序列化&#xff0c;将…...

【最新版】啦啦外卖v64系统独立版源码+全部小程序APP端+安装教程

一.系统介绍 啦啦外卖跑腿平台独立版&#xff0c;使用的都知道该系统功能非常强大&#xff0c;应该说是目前外卖平台功能最全的一套系统。主要是功能非常多&#xff0c;拿来即用&#xff0c;包括客户端小程序、配送端小程序、商户端小程序&#xff0c;还有对应四个端的APP源码…...

13-产品经理-产品多分支平台管理

禅道16.0版本开始&#xff0c;优化和增强了产品的分支/平台功能&#xff0c;主要特点如下&#xff1a; 多分支/平台功能兼容各种大小型项目&#xff0c;项目/迭代可以关联对应产品的某个分支/平台。分支/平台支持灵活管理&#xff0c;可以把分支/平台理解为时间层面的概念&…...

AI在医疗领域的应用

人工智能对医疗领域的革命性影响 一、智能诊断系统的突破 病理识别准确率提升乳腺癌检测准确率达94.6%(2023《Nature Medicine》)皮肤癌诊断灵敏度超过专业医师12%多模态诊断整合融合CT/MRI影像+基因组数据+电子病历急性肾损伤预测提前48小时(DeepMind)二、药物研发范式革…...

LabVIEW 在故障诊断中的算法

在故障诊断领域&#xff0c;LabVIEW 凭借其强大的图形化编程能力、丰富多样的工具包以及卓越的功能性能&#xff0c;成为工程师们进行故障诊断系统开发的得力助手。通过运用各种算法&#xff0c;能够对采集到的信号进行全面、深入的分析处理&#xff0c;从而准确地诊断出系统中…...

(自用)WebSocket创建流程

在Spring Boot项目中新建WebSocket服务&#xff0c;可以按照以下详细步骤进行操作&#xff1a; 1.创建Spring Boot项目 可以通过Spring Initializr&#xff08;<>&#xff09;快速创建一个新的Spring Boot项目&#xff0c;添加Spring Web和Spring Boot DevTools依赖&…...

C++多线程编码二

1.lock和try_lock lock是一个函数模板&#xff0c;可以支持多个锁对象同时锁定同一个&#xff0c;如果其中一个锁对象没有锁住&#xff0c;lock函数会把已经锁定的对象解锁并进入阻塞&#xff0c;直到多个锁锁定一个对象。 try_lock也是一个函数模板&#xff0c;尝试对多个锁…...

【最新版】金媒婚恋系统v10.5最新稳定开源+原生前端小程序 PC端+安装教程

一.系统简介 1. 红娘服务 红娘服务模块是该系统的一大特色。专业红娘会通过分析用户的个人资料和偏好&#xff0c; 为用户提供精准的配对建议和个性化服务。用户可以预约红娘服务&#xff0c;通过红娘的介入&#xff0c;提升配对成功率。 2. 相亲活动 相亲活动模块用于组织和管…...

[spring] spring AOP - 面向切面编程の学习

[spring] spring AOP - 面向切面编程の学习 几年前开始还在被 spring 的八股文时&#xff0c;AOP 就是一个比较热也比较大的点&#xff0c;为了面试确实背过不少&#xff0c;不过 AOP 实现本身做的不多&#xff0c;一方面也是因为 AOP 一旦配置好了基本上就不需要改什么&#…...

JavaScript 中的 Reflect 详解

Reflect 是 ES6引入的一个内置对象&#xff0c;它提供了一系列静态方法来操作对象&#xff0c;这些方法与 Proxy 处理器方法一一对应。Reflect 的设计目的是为了更优雅地操作对象&#xff0c;并统一某些操作的行为。 1. Reflect 的基本特点 1. 不是构造函数&#xff1a;不能使…...

【操作系统】linux常用命令

UP作为一个Linux系统练习两年半的个人练习生&#xff0c;今天分门别类地给大家整理一下常用的Linux命令&#xff0c;祝大家在Linux练习之路一帆风顺。 文件和目录操作 文件查看与编辑 文件查找 文件权限与所有权 进程管理 系统信息与监控 网络管理与诊断...

002 vue组件化编程

文章目录 一般方式全局组件局部组件 组件&#xff08;Component&#xff09;是Vue.js最强大的功能之一 组件也是一个Vue实例&#xff0c;也包括&#xff1a;data、methods、生命周期函数等 组件渲染需要html模板&#xff0c;所以增加了template属性&#xff0c;值就是HTML模板 …...

常见的 JavaScript 框架和库

在现代前端开发中&#xff0c;JavaScript框架和库成为了构建高效、可维护应用程序的关键工具。本文将介绍四个常见的JavaScript框架和库&#xff1a;React、Vue.js、Angular 和 Node.js&#xff0c;并探讨它们的特点、使用场景及适用场合。 1. React — 构建用户界面的JavaScri…...

005_循环结构

循环结构 循环结构的作用和应用场景for循环while循环for和while的使用规范do - while 死循环循环嵌套break、continueRandom生成随机数 循环结构的作用和应用场景 减少代码的重复编写、灵活的控制程序的执行 for循环 for (1初始化语句; 2循环条件; 3迭代语句){4循环体语句(重…...

1110+款专业网站应用程序UI界面设计矢量图标figma格式素材 Icon System | 1,100+ Icons Easily Customize

1110款专业网站应用程序UI界面设计矢量图标figma格式素材 Icon System | 1,100 Icons Easily Customize 产品特点 — 24 x 24 px 网格大小 — 2px 线条描边 — 所有形状都是基于矢量的 — 平滑和圆角 — 易于更改颜色 类别 &#x1f6a8; 警报和反馈 ⬆️ 箭头 &…...

leetcode 368. 最大整除子集 中等

给你一个由 无重复 正整数组成的集合 nums &#xff0c;请你找出并返回其中最大的整除子集 answer &#xff0c;子集中每一元素对 (answer[i], answer[j]) 都应当满足&#xff1a; answer[i] % answer[j] 0 &#xff0c;或answer[j] % answer[i] 0 如果存在多个有效解子集&…...

项目总结之常问的一些问题

1.项目功能介绍&#xff0c;重难点 重难点&#xff1a; mock工具使用&#xff08;涉及到的三方接口过多&#xff0c;由于网络等原因无法调通&#xff0c;所以测试的时候&#xff0c;采用mock工具来模拟返回接口真正调用后响应数据&#xff09; 2.项目负责哪部分&#xff1f;…...

51单片机实现精确定时

一、51单片机代码 #include <reg52.h>sbit LED P3^3;extern bit b10Ms; extern bit b100Ms; extern bit b1S; extern bit b10S;void Timer0_Init() {TMOD | 0x01; // 设置定时器0为模式1TH0 (65536 - 1000) / 256; // 高8位赋初值TL0 (65536 - 1000) % 256; // 低8位…...

记一次不太顺利的Docker重装

#记录工作 一、前言 默认情况下&#xff0c;Windows系统上Docker Desktop 安装在 &#xff1a;C:\Program Files\Docker\Docker&#xff1b; 目前正常下载能下载到最新版本是到v4.39.0&#xff0c;实际已经能找到v4.40.0版本来进行修复安装&#xff1b; 建议尽量不要改变Doc…...

【计网】TCP 协议详解 与 常见面试题

三次握手、四次挥手的常见面试题 不用死记&#xff0c;只需要清楚三次握手&#xff0c;四次挥手的流程&#xff0c;回答的时候心里要记住&#xff0c;假设网络是不可靠的 问题(1)&#xff1a;为什么关闭连接时需要四次挥手&#xff0c;而建立连接却只要三次握手&#xff1f; 关…...

Docker介绍

Docker介绍 Docker 本身并不是容器&#xff0c;而是一个使用容器的工具。容器是 Linux 内核提供的技术&#xff0c;Docker 只是将这种技术的使用简便化了。Docker 的主要目标是 “Build,Ship and Run Any APP,Anywhere”&#xff08;“一次封装&#xff0c;到处运行”&#xf…...

大模型推理--Qwen2.5-Omni在A100上的初体验

过去的一周Qwen2.5-Omni产生了很高的热度&#xff0c;吸引了很多人的目光。它的多模态确实很吸引人&#xff0c;放出来的demo体验还算尚可&#xff08;语音对话的延迟还是太大&#xff09;&#xff0c;所以就在A100 PCIe上实地部署了一下&#xff0c;初步对其速度进行了测试&am…...

二分查找例题

本篇基于b站灵茶山艾府。 34. 在排序数组中查找元素的第一个和最后一个位置 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 [-1, -1]。 你…...

新增一种线性回归的增量学习框架,已更新31个模型!Matlab回归预测大合集又更新啦!

目录 效果图基本介绍程序设计参考资料 效果图 基本介绍 一种线性回归的增量学习框架&#xff0c;程序研究的主要内容是线性回归模型的增量学习实现及其在房价预测中的应用&#xff0c;旨在通过分块处理数据逐步更新模型&#xff0c;以适应动态数据环境并减少计算资源消耗。 详…...

P1025 [NOIP 2001 提高组] 数的划分(DFS)

题目描述 将整数 n 分成 k 份&#xff0c;且每份不能为空&#xff0c;任意两个方案不相同&#xff08;不考虑顺序&#xff09;。 例如&#xff1a;n7&#xff0c;k3&#xff0c;下面三种分法被认为是相同的。 1,1,5; 1,5,1; 5,1,1. 问有多少种不同的分法。 输入格式 n,k …...

SQL Server存储过程和触发器的使用

存储过程 &#xff08;1&#xff09;创建存储过程&#xff0c;使用Employees表中的员工人数来初始化一个局部变量&#xff0c;并调用这个存储过程。 1. Create PROCEDURE test number1 int output --输出参数&#xff0c;可以从程序中返回信息 2. As 3. begin 4. D…...

Elastic 的 OpenTelemetry 分发版(EDOT)现已正式发布:开源、可用于生产环境的 OTel

作者&#xff1a;来自 Elastic Miguel Luna 及 Bahubali Shetti Elastic 自豪地宣布正式发布 Elastic OpenTelemetry 分发版&#xff08;Elastic Distributions of OpenTelemetry - EDOT&#xff09;&#xff0c;其中包含 Elastic 自定义版本的 OpenTelemetry Collector 以及多…...

springMVC-Json交互处理

什么是JSON JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式&#xff0c;目前使用特别广泛。 采用完全独立于编程语言的文本格式来存储和表示数据。 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写&#xff0c;同时也…...

MySQL中的索引

explain关键字&#xff0c; MySQL索引特性 索引的概念 MySQL 索引是一种用于提高数据库查询效率的数据结构 数据库表中存储的数据都是以记录为单位的&#xff0c;如果在查询数据时直接一条条遍历表中的数据记录&#xff0c;那么查询的时间复杂度将会是 O ( N )。索引的价值在…...

AI小白:JavaPython开发环境双轨制搭建指南

文章目录 1 Python深度学习环境配置1.1 Anaconda生态体系建设1.2 JupyterLab高效工作流魔法命令与可视化调试扩展插件配置指南 2 Java深度学习方案&#xff1a;DL4J实战2.1 企业级部署架构设计2.2 集成传统Java系统Spring Boot微服务封装模型性能优化技巧 1 Python深度学习环境…...

《比特城的机密邮件:加密、签名与防篡改的守护之战》

点击下面图片带您领略全新的嵌入式学习路线 &#x1f525;爆款热榜 88万阅读 1.6万收藏 第一章&#xff1a;风暴前的密令 比特城的议会大厅内&#xff0c;首席长老艾德文握着一卷足有半人高的羊皮纸&#xff0c;眉头紧锁。纸上是即将颁布的《新纪元法典》——这份文件不仅内…...

Redis之布隆过滤器

面试场景切入 针对于电话号码问题的痛点 布隆过滤器是什么&#xff1f; 由一个初值都为0的bit数组和多个哈希函数构成&#xff0c;用来快速判断集合中是否存在某个元素。 设计思想 本质就是判断具体数据是否存在于一个大的集合中。布隆过滤器是一种类似Set的数据结构&#…...

这是一份简单优雅的Prompt Engineering教程

Prompt Engineering&#xff08;提示工程&#xff09;是通过精心设计输入文本&#xff08;prompt&#xff09;来引导大型语言模型&#xff08;LLM&#xff09;生成更准确、相关且符合预期的输出的技术。其核心在于通过调整提问的措辞、结构、上下文和附加信息&#xff0c;优化模…...

Java基础 4.6

1.成员方法练习 //编写类A&#xff1a;判断一个数是奇数还是偶数&#xff0c;返回boolean //根据行、列、字符打印对应行数和列数的字符&#xff0c;比如&#xff1a;行4 列4 字符# 则打印相应的效果 public class MethodExercise01 {public static void main(String[] args) …...

DApp实战篇:前端技术栈一览

前言 在前面一系列内容中&#xff0c;我们由浅入深地了解了DApp的组成&#xff0c;从本小节开始我将带领大家如何完成一个完整的DApp。 本小节则先从前端开始。 前端技术栈 在前端开发者速入&#xff1a;DApp中的前端要干些什么&#xff1f;文中我说过&#xff0c;即便是在…...

C++中如何比较两个字符串的大小--compare()函数实现

一、现在有一个问题描述&#xff1a;有两个字符串&#xff0c;要按照字典顺序比较它们的大小&#xff08;注意所有的小写字母都大于所有的大写字母 &#xff09;。 二、代码 #include <bits/stdc.h> using namespace std;int main() {string str1 "apple";…...

c++中的auto关键字

在 C 中&#xff0c;auto 是一个类型推断关键字&#xff08;C11 引入&#xff09;&#xff0c;允许编译器根据变量的初始化表达式自动推导其类型。它极大地简化了代码编写&#xff0c;尤其在涉及复杂类型或模板的场景中。以下是 auto 的详细说明&#xff1a; 1. 基本用法 1.1 …...

zk源码—1.数据节点与Watcher机制及权限二

大纲 1.ZooKeeper的数据模型、节点类型与应用 (1)数据模型之树形结构 (2)节点类型与特性(持久 临时 顺序 ) (3)节点的状态结构(各种zxid 各种version) (4)节点的版本(version cversion aversion) (5)使用ZooKeeper实现锁(悲观锁 乐观锁) 2.发布订阅模式&#xff1…...

交换机和集线器的区别

集线器&#xff08;Hub&#xff09;—— 大喇叭广播站​​ ​​工作原理​​&#xff1a; 集线器像村里的“大喇叭”&#xff0c;收到任何消息都会​​广播给所有人​​。 比如A对B说“你好”&#xff0c;全村人&#xff08;C、D、E&#xff09;都能听到&#xff0c;但只有B会回…...

微服务系统记录

记录下曾经工作涉及到微服务的相关知识。 1. 架构设计与服务划分 关键内容 领域驱动设计&#xff08;DDD&#xff09;&#xff1a; 利用领域模型和限界上下文&#xff08;Bounded Context&#xff09;拆分业务&#xff0c;明确服务边界。通过事件风暴&#xff08;Event Storm…...

同花顺客户端公司财报抓取分析

目标客户端下载地址:https://ft.51ifind.com/index.php?c=index&a=download PC版本 主要难点在登陆,获取token中的 jgbsessid (每次重新登录这个字段都会立即失效,且有效期应该是15天的) 抓取jgbsessid 主要通过安装mitmproxy 使用 mitmdump + 下边的脚本实现监听接口…...

二叉树与红黑树核心知识点及面试重点

二叉树与红黑树核心知识点及面试重点 一、二叉树 (Binary Tree) 1. 基础概念 定义&#xff1a;每个节点最多有两个子节点&#xff08;左子节点和右子节点&#xff09; 术语&#xff1a; 根节点&#xff1a;最顶层的节点 叶子节点&#xff1a;没有子节点的节点 深度&#xf…...

Rocket-JWT鉴权

目录 一、概述 二、相关依赖 三、环境准备 3.1 创建项目 3.2 读取私钥信息 3.3 token数据负载 3.4 生成token 四、Web鉴权 4.1 验证载体 4.2 接收请求 五、总结 Welcome to Code Blocks blog 本篇文章主要介绍了 [Rocket-JWT鉴权] ❤博主广交技术好友&#xff0c;喜…...

2025 年网络安全终极指南

我们生活在一个科技已成为日常生活不可分割的一部分的时代。对数字世界的依赖性日益增强的也带来了更大的网络风险。 网络安全并不是IT专家的专属特权&#xff0c;而是所有用户的共同责任。通过简单的行动&#xff0c;我们可以保护我们的数据、隐私和财务&#xff0c;降低成为…...

横扫SQL面试——PV、UV问题

&#x1f4ca; 横扫SQL面试&#xff1a;UV/PV问题 &#x1f31f; 什么是UV/PV&#xff1f; 在数据领域&#xff0c;UV&#xff08;Unique Visitor&#xff0c;独立访客&#xff09; 和 PV&#xff08;Page View&#xff0c;页面访问量&#xff09; 是最基础也最重要的指标&…...

ctf-show-杂项签到题

下载文件&#xff0c;解压需要密码&#xff0c;用010打开没看出什么 然后用Advanced Archive Password Recovery暴力破解&#xff0c;发现没用 怀疑是伪解密&#xff0c;解压出来发现加密受损用随波逐流修复加密文件 打开修复的加密文件直接得flag flag&#xff1a;flag{79d…...

对解释器模式的理解

对解释器模式的理解 一、场景1、题目【[来源](https://kamacoder.com/problempage.php?pid1096)】1.1 题目描述1.2 输入描述1.3 输出描述1.4 输入示例1.5 输出示例 二、不采用解释器模式1、代码2、“缺点” 三、采用解释器模式1、代码2、“优点” 四、思考1、解释器模式的意义…...