首页 > 系统相关 >【进程间通信】——共享内存

【进程间通信】——共享内存

时间:2024-06-08 22:22:54浏览次数:13  
标签:映射 内存空间 间通信 内存 进程 共享内存 虚拟内存

目录

Unix系统的System-V版本中就引入了三种进程间通信方式,分别是消息队列、共享内存、信号量集。这三种通信方式也被称为System-V IPC对象。

共享内存 (Shared Memory)

前言

​在下文或接下来的讨论中,我将借用了大佬的文章来深化对特定知识点的理解。我非常尊重原创内容和知识产权,如果有任何侵犯版权或不符合规范的地方,请不吝告知。我将立即采取措施进行修正,并确保内容的合法合规使用。感谢您的理解与支持。

在理解共享内存之前,想必在Linux上写过程序的同学之前都会有这么个疑问,你写的程序在运行时占用了多少内存(物理内存)?

通常我们可以通过top命令查看进程占用了多少内存。

image

这里我们深入探讨一下Linux系统中的VIRTRESSHR这三个关键性能指标,它们各自具有独特的含义。

top命令是Linux系统中一个功能强大的性能监控工具,它不仅可以实时显示系统的总体性能,还能深入到每个进程层面,提供详细的CPU使用率、内存使用情况等信息。通过top命令,我们可以轻松获取到每个进程的VIRTRESSHR等关键指标,从而对系统的性能状况有一个全面的了解。

虚拟内存

​首先,我们需要明确区分两个概念:虚拟内存物理内存。虚拟内存是操作系统内核为了管理进程地址空间而设计的一个逻辑上的概念,而物理内存则是实际存在于计算机硬件中的存储空间。一个程序可能拥有很大的虚拟内存空间,但这并不意味着它必然占用大量的物理内存。这是因为虚拟内存空间允许程序访问比物理内存更大的地址范围,而操作系统会根据需要将虚拟内存中的数据实际加载到物理内存中。

虚拟内存的概念至关重要。当我们编写程序,例如C语言程序,并使用gcc编译器进行编译时,编译器分配给程序的地址实际上是虚拟内存空间中的地址。在程序运行之前,这些地址并不对应物理内存中的任何位置。程序运行过程中可能需要的所有指令和数据,都必须首先存在于虚拟内存空间中。

​既然虚拟内存是一个逻辑上的概念,为了让程序能够在物理机器上执行,就必须有一种机制将这些逻辑上的虚拟内存映射到物理内存上(实实在在的RAM内存条上的空间)。这就是操作系统中的页映射表发挥作用的地方。操作系统为系统中的每个进程维护一个独立的页映射表。

​页映射表的工作原理是将程序在运行时需要访问的虚拟内存空间的各个部分,通过页映射表映射到物理内存空间的相应部分。这样,当CPU需要访问某个虚拟内存地址时,它可以通过查找页映射表来找到对应的物理内存地址。这个过程是Linux操作系统分页机制的核心,其中“页(page)”是虚拟内存空间向物理内存空间映射的基本单位。通过这种方式,操作系统能够高效地管理内存资源,确保程序的顺利运行。
image

​图中演示了虚拟内存空间和物理内存空间的映射关系,它们通过 Page Table关联起来,其中虚拟内存空间中着色的部分分别被映射到物理内存空间对应相同着色的部分。而虚拟内存空间中灰色的部分表示在物理内存空间中没有与之对应的部分,也就是说灰色部分没有被映射到物理内存空间中。这么做也是本着“按需映射”的指导思想,因为虚拟内存空间很大,可能其中很多部分在一次程序运行过程中根本不需要访问,所以也就没有必要将虚拟内存空间中的这些部分映射到物理内存空间上。总结一下就是,虚拟内存是一个假象的内存空间,在程序运行过程中虚拟内存空间中需要被访问的部分会被映射到物理内存空间中。虚拟内空间大只能表示程序运行过程中可访问的空间比较大,不代表物理内存空间占用也大。

VIRT表示的是进程虚拟内存空间大小。对应到图中的进程A来说就是A1、A2、A3、A4以及灰色部分所有空间的总和。也就是说VIRT包含了在已经映射到物理内存空间的部分和尚未映射到物理内存空间的部分和。RES表示的是进程虚拟內存空间中已经映射到物理內存空间的那部分的大小。对应到图中的进程A来说就是A1、A2、A3以及A4几个部分空间的总和。所以说,看进程在运行过程中占了多少内存应该看RES的值而不是VIRT的值。SHR是 share(共享)的缩写,它表示的是进程占用的共享内存大小。在上图中我们看到进程A虚拟内存空间中的A4和进程B虚拟内存空间中的B3都映射到了物理内存空间的A4/B3。为什么会出现这样的情况呢?

​其实我们写的程序会依赖于很多外部的动态库(.so),比如libc.so、libd.so等等。这些动态库在内存中仅仅会保存/映射一份,如果某个进程运行时需要这个动态库,那么动态加载器会将这块内存映到对应进程的虚拟内存空间中。多个进程之间通过共享内存的方式相互通信也会出现这样的凊况。这么一来,就会出现不同进程的虚拟内存空间会映射到相同的物理内存空间。这部分物理内存空间其实是被多个进程所共享的,某个进程占用的内存除了和别的进程共享的内存之外就是自己的独占内存了。所以要计算进程独占内存的大小只要用RES的值减去SHR值即可 。

驻留内存

​顾名思义是指那些被映射到进程虛拟内存空间的物理内存。上图中,在系统物理内存空间中被着色的部分都是驻留内存。比如,A1、A2、A3和A4是进程A的驻留内存,B1、B2和B3是进程B的驻留内存。进程的驻留内存就是进程实实在在占用的物理内存。一般我们所讲的进程占用了多少内存,其实就是说的占用了多少驻留内存而不是多少虚拟内存。因为虛拟内存大并不意味着占用的物理内存大。

System V 共享内存

​从上面已经知道了共享内存其实是物理内存中的一段内存空间。所以进程想要一块共享内存必须向操作系统申请一块物理内存,然后映射到虚拟内存。而Linux系统也提供了一系列有关共享内存的函数接口,如 shmget, shmat, shmdt, shmctl 等函数。

函数及其用途

  • shmget

    • 用途:用于创建一个新的共享内存段或获取一个已存在的共享内存段的标识符;

    • 原型int shmget(key_t key, size_t size, int shmflg);

    • @param

      • key_t key: 用于标识共享内存段的键值。可以使用 ftok 函数生成,也可以自己定义。如果使用 IPC_PRIVATE 作为键值,则会创建一个新的共享内存段,且只有调用 shmget 的进程能访问。

      • size_t size: 共享内存段的大小(以字节为单位)。如果共享内存段已经存在,此参数可以为 0。

      • int shmflg: 标志位,控制共享内存段的创建和权限。常用标志包括:

        • IPC_CREAT: 如果共享内存段不存在,则创建一个新的。

        • IPC_EXCL: 与 IPC_CREAT 一起使用,如果共享内存段已经存在,则返回错误。

        • 权限标志:如 0666,表示读写权限。

    • 示例

key_t key = ftok("shmfile", 66);
if (key == -1) {
    fprintf(stderr, "ftok error,errno:%d,%s\n", errno, strerror(errno));
    exit(EXIT_FAILURE);
}
int shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0666);
if (shmid == -1) {
    fprintf(stderr, "shmget error,errno:%d,%s\n", errno, strerror(errno));
    exit(EXIT_FAILURE);
}

注意:申请成功的共享内存段里面存储的内容会被自动初始化为0,并且内核会为每一块创建的共享内存分配一个shmid_ds结构体来记录共享内存的属性和信息。

  • shmat

    • 用途:用于将共享内存段映射到调用进程的虚拟地址空间;

    • 原型void *shmat(int shmid, const void *shmaddr, int shmflg);

    • @param

      • int shmid: 共享内存段的标识符,由 shmget 返回。

      • const void *shmaddr: 指定进程附加共享内存段的地址。通常设为 NULL,让系统自动选择合适的地址。

      • int shmflg: 标志位,控制共享内存段的附加行为。常用标志包括:

        • SHM_RDONLY: 只读模式附加共享内存段。

        • 0: 读写模式附加共享内存段。

char *shmaddr = (char *)shmat(shmid, NULL, 0);
if (shmaddr == (char *)(-1)) {
    fprintf(stderr, "shmat error, errno: %d, %s\n", errno, strerror(errno));
    exit(EXIT_FAILURE);
}

标签:映射,内存空间,间通信,内存,进程,共享内存,虚拟内存
From: https://www.cnblogs.com/Mr--Song/p/18239025

相关文章

  • 进程知识点
    系统编程进程注意:进程是操作系统分配资源的基本单位!操作系统是以进程为单位来分配系统资源的,比如内存空间、CPU使用权等。线程是操作系统调度资源的最小单位!进程包含线程!1.进程的特征进程具有四个基本特征,分别是动态性、并发性、独立性、异步性动态性:进程会在程序运行时......
  • python 多任务之多进程
    多任务优势多个任务同时执行可以大大提高程序执行效率,可以充分利用CPU资源,提高程序的执行效率概念是指在同一时间内执行多个任务多进程概念进程(process)是资源分配的最小单位,他是操作系统进行资源分配和调度运行的基本单位,比如:一个正在运行的程序就是一个进程,如QQ,微信等......
  • 【Linux】进程3——PID/PPID,父进程,子进程
    在讲父子进程之前,我们接着上面那篇继续讲1.查看进程mycode.cmakefile我们在zs_108直接编译mycode.c,直接运行,然后我们转换另一个账号来查看这个进程我们可以通过ps指令来查看进程  我们就会好奇了,第二行是什么?我们查的是第一行的啊那个是指令的ps的进程PID有什......
  • 【Linux】进程4——进程状态
    1.进程状态什么是状态?每个人都有状态——颓废,阳光,积极向上。。。。进程也有状态在操作系统中,由于进程的数量是非常多的,而系统的资源又非常少,所以不可能每一个进程在每时每刻都会处于上处理机运行的状态,所以在系统中应该要为进程维护好相关的状态:运行态,终止态,阻塞态,挂起态,......
  • oracle进程
    每个oracle进程都有自己的任务,oracle会给进程分配内存(PGA)让进程更好的完成任务。oracle进程可以分为三类:服务器进程,后台进程,从属进程。1服务器进程服务器进程是执行客户端会话指令的进程。负责将客户端的指令发送到oracle服务端执行,然后将服务端的结果返回给客户端。可分为......
  • 模块间通信
    在Node.js中,全局对象并不是window,因为Node.js运行在服务器端,而不是浏览器环境中。在Node.js中,全局对象可以通过多种方式访问,但最常见的是使用global关键字。global是Node.js中的全局命名空间对象。它类似于浏览器环境中的window对象,但它是Node.js特有的。......
  • 计算机语言python发展历史进程
    Python语言之父,荷兰人GuidovanRossum。他于1982年从阿姆斯特丹大学取得了数学和计算机硕士学位。20世纪80年代中期,Python之父GuidovanRossum还在CWI(数学和理论计算机科学领域的研究中心,位于阿姆斯特丹)为ABC语言贡献代码。ABC语言是一个为编程初学者打造的研究项目。A......
  • 6/7学习进程
    今天上数据库实验课完成了两次实验实验三数据库完整性、安全性实现一、实验目的:使学生加深对数据库安全性和完整性的理解,并掌握SQLServer中有关用户、角色及操作权限的管理方法,学会创建和使用规则、缺省和触发器以及存储过程。二、实验要求:通过实验对数据进行完整性控......
  • 在Linux中,进程间通信方式有哪些?
    在Linux中,进程间通信(IPC)是允许多个进程或线程交换数据或信号的机制。以下是一些常见的进程间通信方式:1.管道(Pipes)允许一个进程将输出发送到另一个进程的输入。可以是匿名管道或命名管道(FIFOs)。#创建匿名管道mkfifo/tmp/mypipe#使用管道echo"Hello">/tmp/mypipeca......
  • 进程间通信九天学习笔记
    进程间通信九天学习笔记day1:基本进程操作fork()返回pid进程idgetpid()获取当前进程IDsystem()执行系统命令day2:管道匿名管道pipe(intpipefd[2])pipefd[0]读操作pipefd[1]写操作有名管道(FIFO)mkfifo(,0644)open()read()write()day3:信号标准......