【Linux系统编程】程序地址空间

简介: 【Linux系统编程】程序地址空间

进程地址空间


       进程地址空间是指每个进程在计算机内存中所占用的地址空间。地址空间是指能被访问的内存地址范围,它由若干个连续的内存块组成。每个进程都有自己的地址空间,这意味着每个进程都有自己的内存地址范围,不会与其他进程冲突。进程地址空间通常被划分为几个部分,包括代码段、数据段、堆和栈等,它是一种特定的数据结构,进程task_struct内部指向其结构,次结构在系统中叫做mm_struct。具体的结构分布如下图:


5c289a503cf84c07bf17bba10214e7c4.png


下面是在Linux下运用代码演示其地址:


[zhujunhao@bogon code]$ cat test.cpp
#include <iostream>
#include <unistd.h>
#include <cstdio>
using namespace std;
int main()
{
    char* s = new char[5];
    cout << "&s: " << &s << endl;
    int n = 8;
    cout << "&n: " << &n << endl;
    return 0;
}
[zhujunhao@bogon code]$ ./test.exe
//可看出堆区地址高,对应上面进程地址空间
&s: 0x7fff23280dc8
&n: 0x7fff23280dc4


       在vs下的测试可能还不一样,数据可能会出现异常,在Linux下可以测试出。这时因为Windows下出于安全的考虑,可能会对齐做出调整,Linux下也会做出安全考虑,只不过比Windows较为“ 优雅 ”。


物理地址与虚拟地址


       物理地址是系统内存中真正意义上存储数据所对应的一种地址,虚拟地址是模拟来的一种地址,通常与物理地址建立联系,然后从物理地址中对数据做出改变。我们平常使用C/C++中的地址都是虚拟地址。我们先来观察以下代码。


[zhujunhao@bogon code]$ cat code.cpp
#include <iostream>
#include <cstdio>
#include <unistd.h>
using namespace std;
int a = 100;
int main()
{
    pid_t p = fork();
    if (p == 0) {
        cout << "Child:" << endl;
        a = 200;
        cout << "   a = " << a << "  " << "&a = " << &a << endl; 
    }
    else {
        cout << "Father:" << endl;
        cout << "   a = " << a << "  " << "&a = " << &a << endl;
    }
    return 0;
}
[zhujunhao@bogon code]$ g++ -o code.exe code.cpp
[zhujunhao@bogon code]$ ./code.exe
//发现地址一样,但数据不一样
Father:
   a = 100  &a = 0x601074
Child:
   a = 200  &a = 0x601074

       注意,由于数据明显不一样,所以以上的地址不是物理地址,是虚拟地址/线性地址。也就是说,我们所用到的所有地址,全都不是物理地址,是虚拟或线性地址,而物理地址,用户一概看不到,由OS统一管理,其中,OS必须负责将虚拟地址转化成物理地址。


       在以上代码中,当子进程修改变量时,系统将会找到从子进程所对应的进程地址空间中的虚拟地址对应的物理地址,在物理地址内部开辟一块自己存储数据的空间,修改数据时将会修改从虚拟地址到物理地址的眏射表,眏射表将会修改那块存储数据的空间中的数据并重新建立两地址转换间的眏射关系,原本的数据不会被影响,所以,父子进程虽然虚拟地址一样,但数据不一样。


       系统之所以这样设计原因有以下三点:


       1,将物理内存从无序变有序。如果让让进程直接访问内存的话,那么每个进程存在内存中的位置都是不一样的,将会增加操作系统管理的成本。


       2,将内存管理和进程管理进行耦合。虚拟地址负责管理进程,物理地址负责管理内存。


       3,虚拟地址的设计间接保护了内存安全。如若直接访问物理地址,当用户胡乱操作时,将会造成不可逆转的损坏,虚拟地址的使用对其做出了拦截,保证了系统安全。


相关文章
|
3月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
1月前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
2月前
|
运维 Java Linux
【运维基础知识】Linux服务器下手写启停Java程序脚本start.sh stop.sh及详细说明
### 启动Java程序脚本 `start.sh` 此脚本用于启动一个Java程序,设置JVM字符集为GBK,最大堆内存为3000M,并将程序的日志输出到`output.log`文件中,同时在后台运行。 ### 停止Java程序脚本 `stop.sh` 此脚本用于停止指定名称的服务(如`QuoteServer`),通过查找并终止该服务的Java进程,输出操作结果以确认是否成功。
63 1
|
2月前
|
网络协议 Linux 开发工具
linux系统配置固定地址
linux系统配置固定地址
|
3月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
3月前
|
消息中间件 分布式计算 Java
Linux环境下 java程序提交spark任务到Yarn报错
Linux环境下 java程序提交spark任务到Yarn报错
49 5
|
3月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
150 6
|
3月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
161 3
|
3月前
|
Shell Linux Python
python执行linux系统命令的几种方法(python3经典编程案例)
文章介绍了多种使用Python执行Linux系统命令的方法,包括使用os模块的不同函数以及subprocess模块来调用shell命令并处理其输出。
65 0
|
7月前
|
缓存 Linux 测试技术
安装【银河麒麟V10】linux系统--并挂载镜像
安装【银河麒麟V10】linux系统--并挂载镜像
2042 0