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

[Linux]进程地址空间

前言

我们在学习C语言期间,经常可以提及到这些区域,有一个问题:这里的地址空间是内存吗?答案是这里的地址空间并不是内存。这里的地址空间是进程地址空间,下面我们就讲解进程地址空间。

这段空间中自下而上,地址是增长的,栈是向地址减小方向增长(栈是先使用高地址),而堆是向地址增长方向增长(堆是先使用低地址),堆栈之间的共享区,主要用来加载动态库。

接下来我们来说明四个问题:

  1. 验证地址空间的基本排布
  2. 进程地址空间究竟是什么?
  3. 地址空间和物理内存之间的关系
  4. 为什么要存在地址空间?

1.验证地址空间的基本排布

#include<stdio.h>
#include<stdlib.h>
int g_unval;//未初始化
int g_val = 100;//初始化
int main(int argc,char *argv[],char *env[])
{printf("code addr:           %p\n",main);//代码区起始地址const char* p = "hello bit";//p是指针变量(栈区),p指向字符常量h(字符常量区)printf("read only :          %p\n",p);printf("global val:          %p\n",&g_val);printf("global uninit val:   %p\n",&g_unval);char *q = (char *)malloc(10);printf("heap addr:           %p\n",q);printf("stack addr:          %p\n",&p);//p先定义,先入栈printf("stack addr:          %p\n",&q);printf("args addr            %p\n",argv[0]);//命令行参数printf("args addr            %p\n",argv[argc-1]);printf("env addr:            %p\n",env[0]);//环境变量return 0;
}

我们可以看到代码区的地址是最小的,这里就验证了地址空间的基本排布:p和q都是定义在栈区的,p先定义,先入栈,可以看到p的地址大于q,说明了栈是先使用高地址再使用低地址。

这里我们首先得出两点结论:

1、进程地址空间不是内存

2、进程地址空间,会在进程的整个生命周期内一直存在,直到进程退出

(这也就解释了全局变量为什么会一直存在,原因是未初始化数据,初始化数据,这些区域是一直存在的)


 2.进程地址空间究竟是什么?

下面我们通过一个代码来看一个现象,我们定义了一个全局变量,fork创建一个子进程,让父进程和子进程完成自己的任务,在子进程中定义count来计数,当子进程的打印任务进行到第五次时,让子进程将这个全局变量改成100:

#include<stdio.h>
#include<unistd.h>
int g_val = 0;
int main()
{printf("begin.....%d\n",g_val);pid_t id = fork();if(id==0){//childint count = 0;while(1){printf("child: pid: %d,ppid: %d, g_val:%d, &g_val: %p\n",getpid(),getppid(),g_val,&g_val);sleep(1);count++;if(count == 5){g_val = 100;}}}else if(id>0){//fatherwhile(1){printf("father: pod: %d,ppid: %d, g_val:%d, &g_val: %p\n",getpid(),getppid(),g_val,&g_val);sleep(1);}}else{//todo}return 0;
}

代码共享,所以看到前五次打印的g_val的地址都是一样的,这我们不意外,等到了第六次时,我们发现父进程g_val依然是0,子进程的g_val变成了100,因为我们将它改了,这也不意外,因为前面说了,父子进程之间代码共享,而数据是各自私有一份的(写时拷贝),但是令人奇怪的是地址竟然是一样的!

如果我们看到的地址,是物理地址,这种情况可不可能呢?

这是绝对不可能的,如果可能,那么父子进程在同一个地址处读取数据怎么会是不同的值呢?所以,我们曾经所学到的所有的地址,绝对不是物理地址

其实这种地址本质就是一种虚拟地址!

任何我们学过的语言,里面的地址都绝对不会是物理地址,虚拟地址这种地址是由操作系统给我们提供的,操作系统如何给我们提供呢?既然这种地址是虚拟地址,那么一定有某种途径将虚拟地址转化为物理地址,因为数据和代码一定在物理内存上,因为冯诺依曼规定任何数据在启动时必须加载到物理内存,所以肯定需要将虚拟地址转化成物理地址,这里的转化工作由操作系统完成,所有的程序都必须运行起来,运行起来之后,该程序立即变成了进程,那么刚刚打印的虚拟地址大概率和进程有某种关系。

我们在上学期间,经常可能会和同桌画三八线,比如一张课桌是100cm,我们用一把尺子来划分区域,女孩的区域是0,50,男孩的区域是50,100,那么我们再计算机当中怎么描述这个事情呢?我们可以这样定义:

struct area
{unsigned long start;unsigned long end;
};
struct area girl = {0,50};
struct area boy = {50,100};

此时我们就划分好了区域,这时,不管是男孩还是女孩,大脑里都有了这样的一个区域:

当女孩觉得自己活动范围不够,想扩大自己的区域时,就可以调整自己认为的[start,end],划分三八线的过程,就是划分区域的过程,调整区域的过程,本质就是调整自己认为的[start,end]

其中我们将桌子认为是物理内存,男孩和女孩认为是每一个进程,而男孩和女孩本质上都认为自己有一把尺子(脑海里的尺子),这把尺子就是进程地址空间,男孩想放自己的书包、铅笔等物品时,男孩就在自己的进程地址空间再划分区域放自己的物品。

那么如何划分进程地址空间的区域呢?在Linux当中,进程地址空间本质上是一种数据结构,是多个区域的集合。

在Linux内核中,有这样一个结构体:struct mm_struct,在这个结构体去表示我们开始说的一个一个的区域呢?这样去表示:

struct mm_struct
{unsigned long code_start;//代码区unsigned long code_end;unsigned long init_start;//初始化区unsigned long init_end;unsigned long uninit_start;//未初始化区unsigned long uninit_end;unsigned long heap_start;//堆区unsigned long heap_end;unsigned long stack_start;//栈区unsigned long stack_end;//...等等
}

在上面的例子中,男孩脑海里有一把尺子,想着自己拥有桌子的一半,女孩脑海里也有一把尺子,想着自己也拥有桌子的一半,而此时我们改变了:男孩和女孩关系比较好,不进行什么划分三八线,男孩脑海里有一把尺子,想着自己拥有0-100cm的桌子,女孩脑海里有一把尺子,想着自己也拥有0-100cm的桌子,他们在放东西时,只要记住了尺子的刻度就可以了。

为了更深一步的理解进程地址空间,我们再来举一个例子:

比如有一个富豪,他拥有10个亿的身家,这个富豪有10个私生子,这10个私生子互相并不知道自己的存在,富豪对自己的每一个私生子都说孩子你好好学习,老爸现在有10个亿的家产,以后就全是你的,请问在这十个私生子的视觉来看,他们认为他们有多少的家产?当然是10亿,当每个私生子向这个富豪要钱时,只要能接受,富豪肯定都会给,不能接受,富豪可以直接拒绝,在这个例子中富豪给每个私生子脑海里建立了虚拟的10个亿,此时每个私生子都认为自己有10个亿,每个人要的钱都是不一样的。

在这个例子中:富豪称之为操作系统,私生子称之为进程,富豪给私生子画的10亿家产,当前私生子的地址空间,对比言之:操作系统默认会给每个进程构成一个地址空间的概念(32位下,地址空间是从000000…0000到FFFFFF…FFF)4GB的空间,每个进程都认为自己有4GB的空间,每个进程都可以向内存申请空间,只要能接受都会给你,不能接受操作系统会直接拒绝,但是并没有什么影响,进程依旧认为自己有4GB的空间。

再回到男孩和女孩的例子,我们的进程地址空间就相当于是那把尺子,而尺子是有刻度的,进程地址空间也是从全000的地址到全FFF的地址,可以在这上面进行区域划分:比如代码区:[code_start,code_end],比如代码区的地址区间是这个:[0x10000,0x20000],那么区间的每一个地址单位就称为虚拟地址

总结

进程地址空间本质是进程看待内存的方式,抽象出来的一个概念,内核:struct mm_struct,这样的每个进程,都认为自己独占系统内存资源(每个私生子都认为自己独占10亿家产),地址空间区域划分本质:将线性地址空间划分成为一个一个的area,[start,end]。虚拟地址本质,在[start,end]之间的各个地址叫做虚拟地址


 3.地址空间和物理内存之间的关系

我们写了三个程序,将这三个程序运行起来,生成了可执行程序,此时系统存在三个进程,我们有三个task_struct结构体,那么对应的三个进程都有各自的进程地址空间mm_struct,这三个task_struct里面各自会有一个指针指向对应的进程地址空间,我们知道可执行程序运行起来需要将代码和数据加载到内存当中,那么是怎么加载到内存当中的呢?进程将自己的代码和数据首先放在虚拟地址空间的对应的区域,在这其中会有一种表结构,叫做页表,页表的核心工作就是完成虚拟地址到物理地址之间的映射,最终我们的可执行程序的代码和数据可以加载到物理内存的任意位置,因为最终只需要建立代码和数据与物理内存之间的映射关系,就可以通过虚拟地址找到物理内存的对应地址。

不同进程的虚拟地址可以完全一样吗?答案是可以完全一样,因为每个进程都有各自的页表,每个进程都是独立的进行通过各自页表中虚拟地址和物理内存的映射关系去找代码和数据

 

 那么不同进程的虚拟地址在页表中映射的物理地址可能会重吗?答案是不会的,如果会重操作系统就挂掉了,有一种可能性会重,但这是我们可以刻意为之,比如创建子进程,让父子进程代码共享:

总结

虚拟地址和物理空间之间是通过页表完成的映射关系


4.为什么要存在地址空间?

为什么进程不直接访问物理内存呢?这样不行吗?为什么要存在地址空间呢?

1 - 保护物理内存不受到任何进程内地址的直接访问,在虚拟地址到物理地址的转化过程中方便进行合法性校验

在早些时候是没有地址空间的:

如果进程直接访问物理内存,那么看到的地址就是物理地址,而语言中有指针,如果指针越界了,一个进程的指针指向了另一个进程的代码和数据,那么进程的独立性,便无法保证,因为物理内存暴露,其中就有可能有恶意程序直接通过物理地址,进行内存数据的篡改,如果里面的数据有账号密码就可以改密码,即使操作系统不让改,也可以读取。后来就发展出来了虚拟地址空间,那么虚拟地址空间如何避免这样的问题呢?

后来就发展出来了虚拟地址空间,那么虚拟地址空间如何避免这样的问题呢?

由上面我们所了解的知识,一个进程有它的task_struct,有地址空间,有页表,页表当中有虚拟地址和物理内存的映射关系,有了页表的存在,虚拟地址到物理地址的一个转化,由操作系统来完成的,同时也可以帮系统进行合法性检测 

我们在写代码的时候肯定了解过指针越界,我们知道地址空间有各个区域,那么指针越界一定会出现错误吗?

不一定,越界可能他还是在自己的合法区域。比如他本来指向的是栈区,越界后它依然指向栈区,编译器的检查机制认为这是合法的,当你指针本来指向数据区,结果指针后来指向了字符常量区,编译器就会根据mm_struct里面的start,end区间来判断你有没有越界,此时发现你越界了就会报错了,这是其中的一种检查,第二种检查为:页表因为将每个虚拟地址的区域映射到了物理内存,其实页表也有一种权限管理,当你对数据区进行映射时,数据区是可以读写的,相应的在页表中的映射关系中的权限就是可读可写,但是当你对代码区和字符常量区进行映射时,因为这两个区域是只读的,相应的在页表中的映射关系中的权限就是只读,如果你对这段区域进行了写,通过页表当中的权限管理,操作系统就直接就将这个进程干掉。

所以进程地址空间的存在也使得可以通过start和end以及页表的权限管理来判断指针是否合法访问 

2 - 将内存管理和进程管理进行解耦

 操作系统有四种核心管理:

1、进程管理

2、内存管理

3、驱动管理

4、文件管理

这里我们主要讲的是进程管理和内存管理:

如果没有进程地址空间,进程直接访问物理内存,当进程退出时,内存管理需要尽快将该进程回收,在这个过程当中必须得保证内存管理得知道某个进程退出了,并且内存管理也得知道某个进程开始了,这样才能给他们及时的分配资源和回收资源,这就意味着内存管理和进程管理模块是强耦合的,也就是说内存管理和进程管理关系比较大,通过我们上面的理解,如果有了进程地址空间,当一个进程需要资源的时候,通过页表映射去要就可以了,内存管理就只需要知道哪些内存区域(配置)是无效的,哪些是有效的(被页表映射的就是有效的,没有被页表映射的就是无效的),当一个进程退出时,它的映射关系也就没了,此时没有了映射关系,物理内存这里就将该进程的数据设置为无效,所以第二个好处就是将内存管理和进程管理进行解耦,内存管理是怎么知道有效还是无效的呢?比如说在一块物理内存区域设置一个计数器count,当页表中有映射到这块区域时,count就++,当一个映射去掉时,就将count–,内存管理只需要检测这个count是不是0,如果为0,说明它是没人用的。

没有进程地址空间时,内存也可以和进程进行解耦,但是代码会设计的特别复杂,所以最终会有进程地址空间

内存管理是怎么将一些大型数据加载到物理内存的?

内存管理是通过延迟加载的方式加载到物理内存的,什么意思呢?比如说你有一个16GB的大型进程,内存管理首先会给你加载小一部分先供你使用,当你使用完时,会先将进程置为睡眠状态,然后再加载一部分,然后将进程再唤醒,进程再继续使用就可以了。对于用户来说,唯一感觉到的是我的游戏运行的慢了。

 3 - 让每个进程,以同样的方式(虚拟地址),看待代码和数据,明确程序运行的地址

目标文件和可执行程序,本身就已经被划分成为了一个个的区域:

磁盘上的可执行程序分区域的每个大小单位为4KB,每个这个大小的数据称为页帧,在物理内存中的每个大小单位也为4KB,每个这个大小的数据称为页框,那么为什么要分区域呢?因为方便生成可执行程序,在这之后其中有一个链接库的过程,如果可执行程序是乱的,那么这个链接过程非常困难,所以需要分好区域,由此进程地址空间才有了区域划分这样的概念,进程的地址空间连续化,也让顺序语句的执行成为了可能:当前语句的起始地址+当前代码的长度就等于下一条语句的地址。如果没有进程地址空间,因为物理内存空余的地方不一定是连续的空间,可能是零散的,那么将可执行程序的数据加载到内存当中时,那么这些数据就是零散的放在各个位置,而这些位置我们又是不确定的,此时很难找到代码和数据的位置了,进程地址空间的存在,进程地址空间又是进行区域划分的,通过页表的映射关系可以很好的找到物理内存,所以这也是存在地址空间的一个理由:让每个进程,以同样的方式(虚拟地址),明确程序运行的地址

最开始我们的四个问题已经全部讲解完,回到最初的那个问题:为什么父进程和子进程的数据不一样,这个我们不意外,因为数据是私有的,但是地址却也是相同的,这是什么原因呢?到达这里我想这个问题已经显而易见了:

 

 此时g_val的虚拟地址没有变化,而子进程的g_val的虚拟地址对物理内存地址的映射已经发生了变化,指向的数据区的g_val已经变为了100。

其他 

进程和程序有什么区别??

提到进程需要知道这三个东西:task_struct,mm_struct,页表。进程是加载进内存的程序,由进程常见的数据结构(struct task_struct(控制块) && struct mm_struct(地址空间))和代码数据组成 

运行队列、等待队列

ask_struct中是包含了很多的进程链接信息的,本质是把进程PCB进行排队的过程 

若干PCB在一个队列中进行等待使用CPU的资源,该对称为运行队列

若干PCB在一个队列中进行等待访问磁盘的资源,该对称为等待队列

相关文章:

[Linux]进程地址空间

前言 我们在学习C语言期间&#xff0c;经常可以提及到这些区域&#xff0c;有一个问题&#xff1a;这里的地址空间是内存吗&#xff1f;答案是这里的地址空间并不是内存。这里的地址空间是进程地址空间&#xff0c;下面我们就讲解进程地址空间。 这段空间中自下而上&#xff…...

dfs和bfs算法

DFS&#xff08;深度优先搜索&#xff0c;Depth-First Search&#xff09;和 BFS&#xff08;广度优先搜索&#xff0c;Breadth-First Search&#xff09;是图遍历或搜索算法中的两种基本方法。它们在探索图的节点时采用不同的策略&#xff0c;适用于不同的场景。 ### 深度优先…...

跨站请求是什么?

介绍 跨站请求&#xff08;Cross-Site Request&#xff09;通常是指浏览器在访问一个网站时&#xff0c;向另一个域名的网站发送请求的行为。这个概念在 Web 安全中非常重要&#xff0c;尤其是在涉及到“跨站请求伪造&#xff08;CSRF&#xff09;”和“跨域资源共享&#xff…...

【深度学习与大模型基础】第9章-条件概率以及条件概率的链式法则

简单理解条件概率 条件概率就是在已知某件事发生的情况下&#xff0c;另一件事发生的概率。用数学符号表示就是&#xff1a; P(A|B) 在B发生的前提下&#xff0c;A发生的概率。 计算机例子&#xff1a;垃圾邮件过滤 假设你写了一个程序来自动判断邮件是否是垃圾邮件&#xf…...

C++: 获取auto的实际类型

auto a "hello";auto* b "hello";auto& c "hello";上述 a, b, c 类型分别是什么&#xff1f; 在不使用 IDE 提供的 inlay hints 情况下&#xff0c; 可以编译期获取&#xff0c;然后运行时打印出来: 方法&#xff1a; 用 decltype(var)…...

谷歌开源代理开发工具包(Agent Development Kit,ADK):让多智能体应用的构建变得更简

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

揭开人工智能与机器学习的神秘面纱:开发者的视角

李升伟 编译 人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09;早已不再是空洞的流行语——它们正在彻底改变我们构建软件、做出决策以及与技术互动的方式。无论是自动化重复性任务&#xff0c;还是驱动自动驾驶汽车&#xff0c;AI/ML都是现代创新的核…...

35.Java线程池(线程池概述、线程池的架构、线程池的种类与创建、线程池的底层原理、线程池的工作流程、线程池的拒绝策略、自定义线程池)

一、线程池概述 1、线程池的优势 线程池是一种线程使用模式&#xff0c;线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能&#xff0c;而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的任务&#xff0c;这避免了在处理短时间任务时创建与…...

【NumPy科学计算:高性能数组操作核心指南】

目录 前言&#xff1a;技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解关键技术模块技术选型对比 二、实战演示环境配置要求核心代码实现运行结果验证 三、性能对比测试方法论量化数据对比结果分析 四、最佳实践推荐方案 ✅常见错误 ❌调试技…...

软考 系统架构设计师系列知识点之杂项集萃(50)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;49&#xff09; 第78题 著作权中&#xff0c;&#xff08;&#xff09;的保护期不受限制。 A. 发表权 B. 发行权 C. 署名权 D. 展览权 正确答案&#xff1a;C。 所属知识点&#xff1a;旧版…...

实现定长的内存池

池化技术 所谓的池化技术&#xff0c;就是程序预先向系统申请过量的资源&#xff0c;然后自己管理起来&#xff0c;以备不时之需。这个操作的价值就是&#xff0c;如果申请与释放资源的开销较大&#xff0c;提前申请资源并在使用后并不释放而是重复利用&#xff0c;能够提高程序…...

定制一款国密浏览器(7):铜锁和BoringSSL

上一章简单介绍了一下国密算法,本章开始进入实战,进行国密算法的移植。算法的移植以铜锁为蓝本,移植到 BoringSSL 中。 BoringSSL 也是由 OpenSSL fork 而来,那能否修改 Chromium 的源码,使用铜锁库呢?这种方式我也考虑并尝试过,最后发现两者的接口差别太大,Chromium …...

Docker 安装CRMEB陀螺匠教程

首先下载代码到服务器中&#xff0c;打开终端&#xff0c;并切换到项目源码根目录&#xff1a; 通过 Docker compose 启动项目 第一次启动时需要拉取和打包相关镜像&#xff0c;所需时长视网络情况而定&#xff0c;需耐心等待。 配置反向代理 参考 Nginx 配置 Nginx 反向代…...

Java中的static都能用来修饰什么?

在Java编程语言中&#xff0c;static关键字是非常重要的修饰符&#xff0c;可以用于多种不同的地方。可用来修饰变量、方法、代码块以及类。 1.静态变量 定义&#xff1a;静态变量属于类本身&#xff0c;而不是类的任何特定实例&#xff08;new出来的对象&#xff09;。 特点&a…...

词法分析器设计实验

掌握生成词法分析器的方法&#xff0c;加深对词法分析原理的理解。掌握设计、编制并调试词法分析程序的思想和方法。本实验是高级语言程序设计、数据结构和编译原理中词法分析原理等知识的综合。 【实验内容及要求】完善以下代码(红色标注处)并加上注释(蓝色标注处) int Getsym…...

matlab求和∑函数方程编程?

matlab求和∑函数方程编程&#xff1f; 一 题目&#xff1a;求下列函数方程式的和 二&#xff1a;代码如下&#xff1a; >> sum_result 0; % 初始化求和变量 for x 1:10 % 设…...

Vue3.5 企业级管理系统实战(十四):动态主题切换

动态主题切换是针对用户体验的常见的功能之一&#xff0c;我们可以自己实现如暗黑模式、明亮模式的切换&#xff0c;也可以利用 Element Plus 默认支持的强大动态主题方案实现。这里我们探讨的是后者通过 CSS 变量设置的方案。 1 组件准备 1.1 修改 Navbar 组件 在 src/layo…...

Python中for循环及其相关函数range(), zip(), enumerate()等

一、Python中的for循环及其相关函数 Python的for循环是算法竞赛中最常用的迭代工具之一&#xff0c;因其简洁和灵活性非常适合快速实现逻辑。以下详细讲解for循环及相关函数在竞赛中的使用场景。 1. for循环基本语法 Python的for循环用于遍历可迭代对象&#xff08;如列表、…...

数据结构与算法——链表OJ题详解(2)

文章目录 一、前言二、OJ续享2.1相交链表2.2环形链表12.2环形链表2 三、总结 一、前言 哦了兄弟们&#xff0c;咱们上次在详解链表OJ题的时候&#xff0c;有一部分OJ题呢up并没有整理完&#xff0c;这一个星期呢&#xff0c;up也是在不断的学习并且沉淀着&#xff0c;也是终于…...

免费送源码:Java+ssm+MySQL 基于PHP在线考试系统的设计与实现 计算机毕业设计原创定制

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对在线考试等问题&#xff0c;对如何通过计算…...

Android之JNI详解

Android之JNI详解 简介创建项目注册动态注册静态注册 关键词解读基础数据类型引用java对象JNI引用与释放cmake配置文件 简介 JNI&#xff08;Java Native Interface&#xff09; 是 Java 提供的一种编程框架&#xff0c;用于在 Java 应用程序中调用和与用其他编程语言&#xf…...

React Hooks: useRef,useCallback,useMemo用法详解

1. useRef&#xff08;保存引用值&#xff09; useRef 通常用于保存“不会参与 UI 渲染&#xff0c;但生命周期要长”的对象引用&#xff0c;比如获取 DOM、保存定时器 ID、WebSocket等。 新建useRef.js组件&#xff0c;写入代码&#xff1a; import React, { useRef, useSt…...

Java基础知识

概念 请介绍全局变量和局部变量的区别 Java中的变量分为成员变量和局部变量&#xff0c;它们的区别如下&#xff1a; 成员变量&#xff1a; 1. 成员变量是在类的范围里定义的变量&#xff1b; 2. 成员变量有默认初始值&#xff1b; 3. 未被static修饰的成员变量也叫…...

体验智能体构建过程:从零开始构建Agent

1. 什么是智能体&#xff1f; 智能体&#xff08;Agents&#xff09;是一种能够感知环境、做出决策并采取行动来实现特定目标的自主实体。智能体的复杂程度各不相同&#xff0c;从简单的响应式智能体&#xff08;对刺激直接做出反应&#xff09;到更高级的智能体&#xff08;能…...

如何从项目目标到成功标准:构建可量化、可落地的项目评估体系

引言 在项目管理领域&#xff0c;"项目成功"的定义往往比表面看起来更复杂。根据PMI的行业报告&#xff0c;67%的项目失败源于目标与成功标准的不匹配。当项目团队仅关注"按时交付"或"预算达标"时&#xff0c;常会忽视真正的价值创造。本文将通…...

大模型论文:Language Models are Few-Shot Learners(GPT3)

大模型论文&#xff1a;Language Models are Few-Shot Learners(GPT3) 文章地址&#xff1a;https://proceedings.neurips.cc/paper_files/paper/2020/file/1457c0d6bfcb4967418bfb8ac142f64a-Paper.pdf 一、摘要 我们证明了&#xff0c;扩大语言模型的规模在任务无关的 few…...

驱动学习专栏--字符设备驱动篇--1_chrdevbase

字符设备驱动简介 字符设备是 Linux 驱动中最基本的一类设备驱动&#xff0c;字符设备就是一个一个字节&#xff0c;按照字节 流进行读写操作的设备&#xff0c;读写数据是分先后顺序的。比如我们最常见的点灯、按键、 IIC 、 SPI &#xff0c; LCD 等等都是字符设备&…...

muduo库源码分析: TcpConnection

一. 主要成员: socket_&#xff1a;用于保存已连接套接字文件描述符。channel_&#xff1a;封装了上面的socket_及其各类事件的处理函数&#xff08;读、写、错误、关闭等事件处理函数&#xff09;。这个Channel中保存的各类事件的处理函数是在TcpConnection对象构造函数中注册…...

【SLAM】ubuntu 18.04 编译安装 OpenCV 3.2.0 时出现哈希错误

本文首发于❄慕雪的寒舍 1. 前言 1.1. 问题说明 在amd64的ubuntu 18.04 desktop上编译安装 OpenCV 3.2.0 的时候&#xff0c;我遇到了cmake构建错误。错误的核心报错如下 for file: [/home/king/slam/pkg/opencv-3.2.0/3rdparty/ippicv/downloads/linux-808b791a6eac9ed78d32…...

挂马漏洞 asp连接冰蝎webshell (附webshell源码 仅限学习研究)

目录 ASP WebShell代码 代码说明&#xff1a; 部署步骤&#xff1a; 使用冰蝎客户端连接&#xff1a; 注意事项&#xff1a; ASP WebShell代码 <% 冰蝎连接密码&#xff08;需与冰蝎客户端配置一致&#xff09; Dim key key "mysecretkey123" 自定义密码…...

Grafana将弃用AngularJS-我们该如何迁移

AngularJS 弃用时间线 AngularJS 支持已在 Grafana 9 中正式弃用。在 2024 年 5 月发布的 Grafana 11 中&#xff0c;所有 Grafana Cloud 和自托管安装默认关闭该功能。到 Grafana 12 版本时&#xff0c;将完全移除对 AngularJS 的支持&#xff0c;包括配置参数开关 angular_s…...

基于单片机的病房呼叫系统设计

2.1 总体方案设计 本课题为基于单片机的病房呼叫系统设计&#xff0c;在此将整个系统架构设计如图2.1所示&#xff0c;在此采用八个按键模拟8个不同的病房号&#xff0c;再通过8个LED指示灯对病房号的状态进行指示&#xff0c;当用户按键按键时&#xff0c;相应的LED灯会点亮…...

简述一下Unity的UnityWebRequest

UnityWebRequest是Unity引擎中用于处理网络请求的强大工具&#xff0c;尤其适用于与Web服务器进行交互&#xff0c;比如获取数据、上传文件或下载资源等。相较于旧版的WWW类&#xff0c;UnityWebRequest提供了更灵活、更高效的API&#xff0c;支持多种HTTP方法&#xff0c;并能…...

文件操作和IO - 2

目录 Java 中操作文件 File 概述 属性 构造方法 方法 getParent getName getPath getAbsolutePath getCanonicalPath exists isFile isDirectory createNewFile delete deleteOnExit list listFiles mkdir mkdirs 完&#xff01; Java 中操作文件 Java 对于文件操…...

⑪数据中心网络M-LAG实战

一、DeviceA-M-LAG-Mater配置 1、M-LAG 系统配置。 # m-lag mad exclude interface GigabitEthernet1/0/7 m-lag mad exclude interface Vlan-interface100 m-lag mad exclude interface Vlan-interface101 m-lag system-mac 0002-0002-0002 m-lag system-number 1 m-la…...

Win10系统安装WSL2-Ubuntu, 并使用VScode开始工作

本教程基于博主当前需要使用 WSL2(Windows Subsystem for Linux 2) 而编写&#xff0c;将自己使用的经过分享给大家。有什么意见建议敬请大家批评指正。此过程需要打开 Microsoft Store 话不多说&#xff0c;立即开始~ 文章目录 1. 检查系统版本2. 启动 WSL 功能3. 安装Ubuntu4…...

Node.js种cluster模块详解

Node.js 中 cluster 模块全部 API 详解 1. 模块属性 const cluster require(cluster);// 1. isMaster // 判断当前进程是否为主进程 console.log(是否为主进程:, cluster.isMaster);// 2. isWorker // 判断当前进程是否为工作进程 console.log(是否为工作进程:, cluster.isW…...

Window 10使用WSL2搭建Linux版Android Studio应用开发环境

一、背景 公司基于高通SA8155、SA8295等车载芯片进行座舱系统开发,使用repo统一管理系统及应用源码仓库。 Android应用端使用Ubuntu环境Android Studio进行开发,使用repo进行平台性管理,包含所有应用仓库。由于gradle配置使用了linux下文件软链接,无法直接使用Window环境…...

PostgreSQL 的统计信息

PostgreSQL 的统计信息 PostgreSQL 的统计信息是查询优化和性能调优的基础&#xff0c;系统通过多种统计信息来评估数据分布和访问模式&#xff0c;从而生成高效的执行计划。 一 统计信息类型与用途 1.1 核心统计类别 统计类型存储位置主要用途更新机制表和索引扫描统计pg_…...

【Linux】Linux基础指令

Linux系统初步介绍 Linux是一种自由和开放源代码的类UNIX操作系统,该操作系统的内核由林纳斯托瓦兹在1991年首次发布,之后,在加上用户空间的应用程序之后,就成为了Linux操作系统&#xff61; 严格来讲,Linux 只是操作系统内核本身,但通常采用“Linux内核”来表达该意思&#…...

【SLAM】在ORB_SLAM2的ROS模式下使用RealSense D435相机

本文介绍了如何在ORB_SLAM2项目中使用RealSense D435相机作为RGB-D输入源&#xff0c;包括ROS下启动D435相机、ORB_SLAM2订阅Topic、ORB_SLAM2读取realsense-viewer录制的rosbag文件等步骤。。 本文首发于❄慕雪的寒舍 1. 前言 先前已经编写了如何用TUM数据集运行ORB_SLAM3以及…...

scapy使用

https://scapy.readthedocs.io/en/latest/introduction.html 在 Mac 上使用 Scapy 抓取特定 IP 的流量并保存到 a.pcap 的步骤如下&#xff1a; 步骤 1&#xff1a;安装 Scapy 在终端中执行以下命令安装&#xff1a; pip install scapy步骤 2&#xff1a;创建 Python 脚本 …...

C2000 系统控制(4) — CPU Memory

CPU 内存 内存控制器 在 C2000 实时微控制器上&#xff0c;RAM 具有不同的特性。这些特性包括&#xff1a; CPU 专用&#xff1a;M0、M1 RAMCPU 和 CLA 共享&#xff1a;LSx RAMCPU、DMA 和 HIC 共享&#xff1a;GSx RAM用于在处理器之间发送和接收消息&#xff1a;MSG RAM …...

Linux网络编程——详解网络层IP协议、网段划分、路由

目录 一、前言 二、IP协议的认识 1、什么是IP协议&#xff1f; 2、IP协议报头 三、网段划分 1、初步认识IP与路由 2、IP地址 I、DHCP动态主机配置协议 3、IP地址的划分 I、CIDR设计 II、子网数目的计算 III、子网掩码的确定 四、特殊的IP地址 五、IP地址的数量限…...

解析医疗器械三大文档:DHF、DMR与DHR

医疗器械的 DHF、DMR 和 DHR 是质量管理体系&#xff08;QMS&#xff09;中的核心文件&#xff0c;贯穿产品全生命周期&#xff0c; 确保医疗器械的安全性、有效性和合规性。 一、三大文件的定义与法规依据 缩写全称法规依据&#xff08;以 FDA 为例&#xff09;核心目的DHF…...

SQL 全文检索原理

全文检索(Full-Text Search)是SQL中用于高效搜索文本数据的技术&#xff0c;与传统的LIKE操作或简单字符串比较相比&#xff0c;它能提供更强大、更灵活的文本搜索能力。 基本概念 全文检索的核心思想是将文本内容分解为可索引的单元(通常是词或词组)&#xff0c;然后建立倒排…...

基于Rosen梯度投影法的约束优化问题求解及MATLAB实现

摘要 在工程优化、经济建模等领域&#xff0c;约束优化问题普遍存在&#xff0c;其核心是在满足线性或非线性约束条件下求解目标函数的极值。本文聚焦Rosen梯度投影法&#xff0c;系统阐述其算法原理、实现步骤及MATLAB编程方法。 关键词&#xff1a;Rosen梯度投影法&#xf…...

Model Context Protocol (MCP) - 尝试创建和测试一下MCP Server

1.简单介绍 MCP是Model Context Protocol的缩写&#xff0c;是Anthropic开源的一个标准协议。MCP使得大语言模型可以和外部的数据源&#xff0c;工具进行集成。当前MCP在社区逐渐地流行起来了。同时official C# SDK(仓库是csharp-sdk) 也在不断更新中&#xff0c;目前最新版本…...

Linux上位机开发实践(关于Qt的移植)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 linux平台上面&#xff0c;很多界面应用&#xff0c;都是基于qt开发的。不管是x86平台&#xff0c;还是arm平台&#xff0c;qt使用的地方都比较多。…...

Node.js 项目 用 `Docker Compose` 发布的完整流程

Node.js 项目 用 Docker Compose 发布的完整流程 ✅ 一、基本项目结构示例 以一个简单 Express 项目为例&#xff1a; my-node-app/ ├── app.js # 启动文件 ├── package.json ├── package-lock.json ├── Dockerfile # 构建 Node 容器 ├…...