《Linux从练气到飞升》No.16 Linux 进程地址空间

🕺作者: 主页

我的专栏
C语言从0到1
探秘C++
数据结构从0到1
探秘Linux
菜鸟刷题集

😘欢迎关注:👍点赞🙌收藏✍️留言

🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢阅读!!!

文章目录

    • 前言
    • 程序地址空间回顾
      • 示例一
      • 示例二
        • 原因:
    • 什么是地址空间?
      • 小故事
      • 历史上的地址 VS 现在的地址
      • 虚拟地址
        • 1.什么是虚拟地址?
        • 2. 什么是页表?
        • 3. 遗留问题
        • 4. 当我们的程序编译的时候,形成可执行程序的时候,还没有被加载到内存中的时候,请问我们程序内部有地址吗?
        • 5. 程序从编译到执行的过程中,步骤是什么样的?
      • 地址空间的概念
    • 为什么要有地址空间?
      • 1. 隔离和保护
      • 2. 资源管理
      • 3. 内存分布有序化
    • 重新理解什么是挂起?

前言

当你在电脑上运行一个程序时,你可能想知道它是如何在内存中存储和管理数据的。有没有一种方法可以使不同的程序在内存中有自己的专属空间,相互之间不会相互干扰呢?

今天,我们将探索一个令人着迷的概念——进程地址空间。进程地址空间是计算机系统中一项至关重要的技术,它为每个正在运行的程序提供了独立的内存空间,用于存储代码、数据和堆栈等信息。

想象一下,当你同时打开多个应用程序,如浏览器、音乐播放器和游戏时,它们能够在内存中各自存在而不相互干扰。这得益于进程地址空间的隔离和管理。通过进程地址空间,不同的程序拥有自己的内存区域,彼此之间不会相互干扰,从而确保了计算环境的稳定性和安全性。

了解进程地址空间的概念将帮助你更好地理解程序的执行过程、内存管理以及如何避免程序之间的相互影响。它在操作系统、编程和软件开发中都有着重要的应用。通过本次学习,我们将揭开进程地址空间的神秘面纱,探索其在计算机系统中的重要性和实际应用。

现在,让我们一起深入了解进程地址空间,探索程序运行背后的奥秘吧!

研究背景:5.14.0-344.el9.x86_64

程序地址空间回顾

示例一

在我们之前学习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[])
{// int a = 10;//字面常量const char *str = "helloworld";// 10;// 'a';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;//static的本质是将该变量开辟在全局区域。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 stack 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;
}

结果如下:
在这里插入图片描述

我们还能看到栈向下增长,所以后面的变量地址就越小,而堆向上增长,后面的变量地址就越大。堆和栈是相对而生的,因为他们之间有相当大的一块空间是共享的。

但是我们知道free是在堆上申请空间的,free时只传入堆起始地址,怎么知道要删除几个字节呢?其实在malloc时会把它的属性数据存起来,包括大小、地址等。

我们还需要了解到。用户空间是0~3GB,内核空间是3GB到4GB。

============================================================================

示例二

这里还要讲述一个例子,一开始有一个进程,后来 fork 成了两个,我们在子进程中修改全局变量的值。我们会发现最后子进程的值和父进程的值不相同,但是地址相同,为什么?怎么可能同一个地址同时读取的时候出现了不同的值呢

测试代码如下:

#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);}}
}

测试结果如下:
在这里插入图片描述

我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:

  • 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量
  • 地址值是一样的,说明该地址绝对不是物理地址
  • 在Linux地址下,这种地址叫做 虚拟地址
  • 我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理

原因:

这里原因也和虚拟地址有关。当我们子进程没有改变父进程的那个全局变量的时候,他们在同一块内存中,但是如果子进程改变了全局变量的值,就会发生写时拷贝,他就到了另一块物理内存上了,但是这两块物理内存所对应的虚拟地址是同一个,也就造成了这样的现象。

在Linux和windows上面验证上面的代码,可能会跑出不一样的结果,我们上面的结论默认只在Linux上有效。

什么是地址空间?

小故事

我们通过一个故事来学习它。

从前有一个大富翁,他有三个孩子。这个大富翁非常富有,拥有很多钱和财产。为了激励他的孩子们,他给每个孩子画了一个大饼。这个大饼代表了10亿美元的财富。每个孩子都认为自己拥有这10亿美元。

大富翁告诉大女儿,她将来会继承家族的产业,成为家族的掌门人。大女儿非常高兴,她开始努力学习,为将来的责任做准备。

大富翁告诉二女儿,她将来会接管他的生意,成为一位成功的商人。二女儿也非常兴奋,她开始学习商业知识,努力提升自己的能力。

大富翁告诉小儿子,他将来会成为街上最亮眼的人。小儿子非常开心,他开始锻炼自己的才艺,努力成为一个出色的表演者。

每个孩子都根据自己拥有10亿美元的想法,制定了自己的计划。大女儿想要投资房地产,二女儿想要扩大生意,小儿子想要在表演领域取得成功。

然而,事实上,这10亿美元只是大富翁给孩子们画的一个饼,他并没有真正给他们这笔钱。但是,每当孩子们向大富翁要钱时,大富翁通常会给他们一些零花钱。因此,每一个人都认为自己是富翁的合法继承人。但是站在上帝视角,我知道他们彼此的存在。我也知道,他们并不是唯一的合法继承人。但是这个老爹给儿子画的饼,我们就叫做地址空间。那么我们现实之中的饼相当于谁呢?他是看得见摸得着的,它叫做物理内存。

我们前面讲述操作系统的时候,讲过先描述再组织,那这里的地址空间就是我们所说的描述,但是他在将来也一定是一种数据结构,要和一个特定的进程关联起来。

历史上的地址 VS 现在的地址

其实在一开始的时候,并没有地址空间这个概念,地址访问的直接就是物理内存,这样的话内存本身是随时可以被读写的,他特别不安全,假如有野指针等问题就很麻烦。

但是现代计算机提出了下面这种方式:
在这里插入图片描述

他引入了虚拟地址的概念。将虚拟地址与物理地址映射起来,要访问物理内存就需要先映射,有人可能会说,最终还是会访问物理内存的,万一我的虚拟地址是一个非法地址呢?

不要急,这时候操作系统会禁止映射就像小时候。你的父母可能会让你把你的压岁钱上交,说存在他那里,怕你弄丢了,等你什么时候要用的时候再给你,但是当你想买玩具的时候,想买很多玩具的时候,你妈觉得那不是必要的,就不会同意,不管你怎么撒泼打滚,是一个道理。

虚拟地址

1.什么是虚拟地址?

其实如硬盘,网卡等外设也有寄存器,我们想把内存的存储空间和外设的寄存器统一编制成当做内存看,但每一个硬件的本身是不同的,所以就需要引入一个虚拟地址空间的东西,它将不同的硬件对应的设备进行编制,所以实际上我们访问的某些硬件是它和虚拟地址就是这样一个关系。

几乎所有的语言,如果他有地址的概念,这个地址一定不是物理地址,而是虚拟地址,一般我们碰不到物理地址,操作系统设计者怕我们误操作导致系统崩溃。

在这里插入图片描述

我们看上面的地址空间。它划分有栈区、共享区、堆区、被初始化数据区等区域。但是我们不用看也知道,为了有效管理内存资源、提供程序运行所需的运行环境,并确保不同程序之间的互相隔离和安全性,他肯定会划分成各个区域的。

事实也的确如此,我们看源码:
在这里插入图片描述

我们会发现它是有通过start或者end的标记值来划分区域。所谓的区域划分本质就是在一个范围里定义startend

所以到现在我们应该知道地址空间,它一定是一种数据结构,而且它里面要有各个区域的划分。我们要知道,每个进程都有他自己的地址空间。该地址空间包含了各种内存区域,如代码段、数据段、堆、栈等。这些区域在进程运行期间可以动态地进行分配和释放。

需要注意的是,不同进程的地址空间可以具有相同的布局,即相同的内存区域类型和相似的地址段,但它们在逻辑上是独立的,相互之间不会干扰或共享内部数据。每个进程都有自己的独立地址空间,使得进程可以在同一台计算机上独立地运行并与其他进程隔离开来。

2. 什么是页表?

页表是处理地址空间和物理内存对应的一种数据结构,是地址空间对象的重要组成部分,用于将进程的虚拟地址映射到物理内存。页表中的每个表项记录了虚拟页和物理页之间的映射关系。当进程访问虚拟地址时,操作系统会根据页表的映射关系将虚拟地址转化为物理地址,从而访问对应的物理内存。

3. 遗留问题

在前面的文章中,我们讲述到fork之后return会被执行两次,它的本质就是对ID进行写入,此时发生了写时拷贝,所以父子进程各自其实在物理内存中有属于自己的变量空间,只不过在我们看到的它是用同一个变量,也就是说,同一个虚拟地址来标识了。
在这里插入图片描述

在fork函数中,父进程和子进程都会执行fork函数内部的return语句。这是因为return语句是一条语句,它在执行时会被两个指令分别执行。所以,当fork函数内部的return语句被执行时,它会被父进程和子进程各自执行一次。

这样的执行机制导致了fork函数的返回值有两个,分别是父进程的返回值和子进程的返回值。父进程的返回值是子进程的进程ID,而子进程的返回值是0。

需要注意的是,当执行return语句时,实际上是对ID进行写入操作。尽管这个ID只有一个是属于父进程的,但是当fork成功之后,当执行return语句时,会发生写入操作,写入之后,父进程和子进程都会执行if和else判断。父进程在判断时使用的是自己的ID,而子进程在判断时使用的是自己的ID。这是因为在fork函数内部的return语句执行时,对ID的写入操作发生了写时拷贝,所以父进程和子进程各自拥有自己的ID。

4. 当我们的程序编译的时候,形成可执行程序的时候,还没有被加载到内存中的时候,请问我们程序内部有地址吗?

答案是已经有地址了。地址空间不仅仅理解成为是操作系统要遵守的,其实编译器也要遵守,在编译器编译代码的时候,就已经给我们形成了各个区域代码区,数据区的,并且采用了和Linux内核中一样的编址方式,给每一个变量,每一行代码都进行了编址,故,程序在编译的时候,每一个字段早已经具有了一个虚拟地址。

在编译器的视角里,在一个程序内部的各种地址关系,其实这个地址不叫做虚拟地址,它叫做逻辑地址。只不过在 Linux 下,逻辑地址、线性地址和物理地址其实是一模一样的,因为我们的 Linux 认为所有的那么起始地址全部都是从 0 开始的。

可执行程序在编译阶段就已经具有地址。在编写C或C++代码时,编译器会为每个函数和变量分配对应的地址。这些地址是相对于程序内部的,可以理解为虚拟地址。编译器会根据程序的结构和代码逻辑,为每个函数和变量分配合适的地址。

当程序被加载到内存中时,操作系统会为其分配一块地址空间,这个地址空间是操作系统给进程分配的,也被称为虚拟地址空间。在这个虚拟地址空间中,程序的代码、数据和其他区域会被映射到对应的物理地址上。

因此,可以说在程序编译阶段,程序内部已经具有地址,这些地址是相对于程序内部的虚拟地址。当程序加载到内存后,操作系统会将虚拟地址映射到物理地址上,使得程序可以在内存中正确执行。

5. 程序从编译到执行的过程中,步骤是什么样的?

a. 编译,将每个函数和变量分配对应的地址,这个地址是虚拟地址
b. 加载,程序被加载到内存中,操作系统会为其分配一块地址空间,这个地址空间是操作系统给进程分配的,也被称为虚拟地址空间。程序会把自己编译时分配的虚拟地址与地址空间的虚拟地址相对应,在这个虚拟地址空间中,程序的代码、数据和其他区域会被映射到对应的物理地址上。
c. 运行,task_struct会被加载到CPU中,CPU在运行过程中需要调用哪一个函数,就会通过虚拟地址找到对应的物理地址,然后调用该函数,调用该函数后也会通过页表、地址空间、PCB来返回对应的地址,往复循环。

地址空间的概念

地址空间是操作系统为进程专门设计的一种内核数据结构。它是进程在运行时所使用的虚拟内存空间的抽象表示。在计算机系统中,每个进程都有自己独立的地址空间,用于存储程序的指令、数据和堆栈等信息。

地址空间的定义包括了进程的线性区域的划分每个区域由起始地址和结束地址来标定。这些区域可以包括代码段、数据段、堆和栈等。每个区域内的地址可以不连续,但在指定的范围内都可以被访问。
在这里插入图片描述
地址空间的设计目的是为了提供一种抽象的方式来管理进程的内存使用。它使得每个进程都可以拥有自己独立的地址空间,而不会相互干扰。通过地址空间的映射机制,操作系统可以将进程的虚拟地址转化为物理内存地址,从而避免了进程对内存的直接访问
在这里插入图片描述
总之,地址空间是操作系统为进程提供的一种抽象概念,用于管理进程的内存使用。它定义了进程的虚拟内存空间的划分和映射机制,确保每个进程都可以独立地访问自己的内存空间,保证了进程之间的隔离和安全性。

为什么要有地址空间?

1. 隔离和保护

  • 凡是非法的访问或者映射操作系统都会识别到并终止你这个进程,
  • 可以有效的保护物理内存,因为地址空间和页表是操作系统创建并维护的,
  • 也就意味着凡是想使用地址空间和页表进行映射,也一定要在操作系统的监管之下来进行访问,
  • 他还保护了物理内存中所有的合法数据,包括各个进程以及内核的相关有效数据。

2. 资源管理

因为有地址空间的存在,也因为有页表的映射的存在,我们的物理内存中是不是可以对未来的数据进行任意位置的加载?

当然可以,物理内存的分配可以做到和进程的管理没有关系。这样就实现了内存管理模块和进程管理模块的解耦合。

所以我们在C、C++语言上new和malloc空间的时候,本质是在虚拟地址空间上申请的。试想一下,如果我申请了物理空间,但是我不立马使用,是不是就会造成了空间的浪费了?当然会。 而本质上因为有地址空间的存在,上层申请空间其实是在地址空间上申请的,物理内存可以甚至一个字节都不给你,而当你真正进行对物理地址空间访问的时候,才执行内存的相关管理算法,帮你申请内存构建列表映射关系。然后再让你进行内存的访问。而对物理地址空间访问是由操作系统自动完成的,用户包括进程完全灵感知。这样也就是延迟分配的策略,它可以提高整机的效率,它使内存的有效使用几乎为100%。有了地址空间的存在,我们可以以有序化的视角去看待进程的代码和数据在物理内存中的分布情况。这样可以更好地确定代码和数据的起始地址,并且便于操作系统进行统一管理。同时,有序化的内存分布也使得我们能够更好地检测越界访问等问题。

3. 内存分布有序化

因为在物理内存中理论上可以任意位置的加载,那是不是物理内存中的几乎所有的数据和代码在内存中是乱序的呢?

确实如此,因为有页表的存在,它可以将地址空间上的虚拟地址和物理地址进行映射。

他就可以做到说,所有的内存分布有序化。我们知道地址空间是操作系统给进程画的大饼。

进程的独立性可以通过地址空间加页表的方式实现,结合上一条来说,进程要访问的物理内存中的数据和代码,可能目前并没有在物理内存中存在,也可以让不同的进程映射到不同的物理内存,这样就很容易实现了进程的独立性。

因为有地址空间的存在,每一个进程都认为自己拥有4GB空间,并且各个区域是有序的。进而可以通过列表映射到不同的区域来实现进程的独立性,每一个进程不知道,也不需要知道其他进程的存在。

重新理解什么是挂起?

加载的本质就是创建进程,那么是不是非得立马把所有的程序的代码和数据加载到内存中,并创建内核数据结构,建立映射关系?

不是这样的,在最极端情况下,只有内核结构被创建出来了,是什么情况的,此时,他并没有被调用的时候,就是这种情况,这个状态也就是新建状态,理论上我们是可以实现对程序的分批加载的,既然可以分批加载,当然也可以分批换出。进程的数据和代码被换出了,就叫做挂起了。

页表映射的时候不仅仅映射的是内存,磁盘中的位置也可以映射。

比如说加载一些大型的游戏,如果一次性全部加载,物理内存肯定是不够的,然而我们分批加载,加载了一部分,又换出一部分,如此往复便实现了游戏的加载。还有就是当我们加载游戏时。某个进程可能需要等待其他资源,甚至这个进程短时间不会再被执行了,他此时的状态就是阻塞了,他此时可能就会把物理内存唤出到磁盘中,等待下一次的唤入。

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

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

相关文章

node没有自动安装npm时,如何手动安装 npm

之前写过一篇使用 nvm 管理 node 版本的文章&#xff0c;node版本管理&#xff08;Windows&#xff09; 有时候&#xff0c;我们使用 nvm 下载 node 时&#xff0c;node 没有自动下载 npm &#xff0c;此时就需要我们自己手动下载 npm 1、下载 npm下载地址&#xff1a;&…

Docker创建 LNMP 服务+Wordpress 网站平台

Docker创建 LNMP 服务Wordpress 网站平台 一.环境及准备工作 1.项目环境 公司在实际的生产环境中&#xff0c;需要使用 Docker 技术在一台主机上创建 LNMP 服务并运行 Wordpress 网站平台。然后对此服务进行相关的性能调优和管理工作。 容器 系统 IP地址 软件 nginx centos…

数据结构算法--4堆排序

堆排序过程: >建立堆(大根堆) >得到堆顶元素&#xff0c;为最大元素 >去掉堆顶&#xff0c;将堆最后一个元素放到堆顶&#xff0c;此时可通过一次调整使堆重新有序 >堆顶元素为第二大元素 >重复步骤3&#xff0c;直到堆变空 此时是建立堆后的大根堆模型 将…

Docker容器:docker数据管理、镜像的创建及dockerfile案例

文章目录 一、docker数据管理1.为何需要docker数据管理2.数据管理类型3.数据卷4.数据卷容器5.容器的互联 二.docker镜像的三种创建方法1.基于现有镜像创建1.1 启动镜像1.2 生成新镜像 2.基于本地模板创建2.1 OPENVZ 下载模板2.2 导入容器生成镜像 3.基于dockerfile创建3.1 dock…

ChatGPT、Google Bard、Claude2、新BING哪一款人工智能聊天机器人适合自己

人工智能聊天机器人正在提高数无数专业人士的工作效率。下面我们就来看看目前最流行的几款强大的人工智能工具&#xff0c;以及它们具体如何帮助到你。 今年7月AI圈最大的动静之一便是AI初创公司Anthropic发布了其AI聊天机器人Claude最新版本——Claude2。该聊天机器人对标Open…

Excel/PowerPoint条形图改变顺序

条形图是从下往上排的&#xff0c;很多时候不是我们想要的效果 解决方案 选择坐标轴&#xff0c;双击&#xff0c;按下图顺序点击 效果

机器学习分类,损失函数中为什么要用Log,机器学习的应用

目录 损失函数中为什么要用Log 为什么对数可以将乘法转化为加法&#xff1f; 机器学习&#xff08;Machine Learning&#xff09; 机器学习的分类 监督学习 无监督学习 强化学习 机器学习的应用 应用举例&#xff1a;猫狗分类 1. 现实问题抽象为数学问题 2. 数据准备…

Docker容器:docker镜像的创建及dockerfile案例

文章目录 一.docker镜像的三种创建方法1.基于现有镜像创建1.1 启动镜像1.2 生成新镜像 2.基于本地模板创建2.1 OPENVZ 下载模板2.2 导入容器生成镜像 3.基于dockerfile创建3.1 dockerfile结构及分层3.2 联合文件系统3.3 docker镜像加载原理及过程 4.dockerfile操作常用的指令4.…

蓝奥声智能工业安全用电监测与智慧能源解决方案

能源管理变得越来越重要。如今&#xff0c;能源成本已成为国内预算的核心因素&#xff0c;因此用电监控对大多数现代企业来说都很重要。许多企业在日常能源消耗监控中面临着一些挑战&#xff0c;因为它们的规模庞大&#xff0c;基础设施多样化&#xff0c;灵活性低&#xff0c;…

更好的 3D 网格,从重建到生成式 AI

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可二次编辑的3D应用场景 这些生成的 3D 模型通常提取为标准三角形网格。网格表示提供了许多好处&#xff0c;包括支持现有软件包、高级硬件加速和支持物理仿真。但是&#xff0c;并非所有网格都是平等的&#xff0c;这些优势只…

Linux系统下消息中间件RocketMQ下载、安装、搭建、配置、控制台rocketmq-dashboard的安装保姆级教程 rocketmq ui

这里给出我使用的 RocketMQ 版本&#xff08;5.1.3&#xff09;、RocketMQ-Dashboard 版本的百度网盘链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1HaKBBDGWZ0WKLGgVwIG9pw 提取码&#xff1a;1234 文章目录 一. 官网下载安装二、启动NameServer三、启动Broker四…

Elasticsearch 查询之Function Score Query

前言 ES 的主查询评分模式分为两种&#xff0c;是信息检索领域的重要算法&#xff1a; TF-IDF 算法 和 BM25 算法。 Elasticsearch 从版本 5.0 开始引入了 BM25 算法作为默认的文档评分&#xff08;relevance scoring&#xff09;算法。在此之前&#xff0c;Elasticsearch 使…

uniapp 顶部头部样式

<u-navbartitle"商城":safeAreaInsetTop"true"><view slot"left"><image src"/static/logo.png" mode"" class"u-w-50 u-h-50"></image></view></u-navbar>

Certify The Web (IIS)

一、简介 Certify The Web 适用于 Windows的SSL 证书管理器用户界面&#xff0c;与所有 ACME v2 CA 兼容&#xff0c;为您的 IIS/Windows 服务器轻松地安装和自动更新来自 Letencrypt.org 和其他 ACME 证书授权机构的免费 SSL/TLS 证书&#xff0c;设置 https 从未如此简单。 …

【中危】PowerJob 未授权访问漏洞 (CVE-2023-36106)

漏洞描述 PowerJob 是一款开源的分布式任务调度框架。 在 PowerJob 受影响版本中存在错误的访问控制漏洞。由于没有对/container/list接口做鉴权&#xff0c;未授权的攻击者可以构造 appId 参数访问 /container/list接口获取应用容器的标识、运行状态、日志等敏感信息。 漏洞…

java+springboot+mysql小区自来水实时监控管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的小区自来水实时监控管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、用户角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;楼栋管理&#xff1b;租户管理、用水管理&…

糖尿病视网膜病变,黄斑病变,年龄相关检测研究(Matlab代码)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【Git分支操作---讲解二】

Git分支操作---讲解二 查看分支创建分支切换分支修改分支切换分支合并分支合并分支【冲突】(只会修改主分支不会修改其他分支)什么时候会有冲突&#xff1f; 查看分支 创建分支 切换分支 修改分支 切换分支 合并分支 合并分支【冲突】(只会修改主分支不会修改其他分支) 什么时…

python 打印沁园春 雪 居中对齐 文本对齐

以下是python 中使用 DebugInfo 模块居中对齐打印《沁园春・雪》的效果 引入模块 pip install DebugInfopython代码 # -*- coding:UTF-8 -*-# region 引入必要依赖 from DebugInfo.DebugInfo import * # endregion诗文 沁园春 雪 作者: 毛主席 北国风光&#xff0c;千里冰封…

Blazor前后端框架Known-V1.2.13

V1.2.13 Known是基于C#和Blazor开发的前后端分离快速开发框架&#xff0c;开箱即用&#xff0c;跨平台&#xff0c;一处代码&#xff0c;多处运行。 Gitee&#xff1a; https://gitee.com/known/KnownGithub&#xff1a;https://github.com/known/Known 概述 基于C#和Blazo…