Linux进程地址空间 零、前言 一、程序内存空间 二、进程地址空间 1、引入及概念 2、进程地址空间 3、相关问题 零、前言 本章主要讲解学习进程地址空间的知识 一、程序内存空间 在学习C/C ,说明该地址绝对不是物理地址,因为是物理地址根本不会有这种事发生 2、进程地址空间 概念: 在Linux地址下,这种地址叫做 虚拟地址,我们在用C/C++语言所看到的地址,全部都是虚拟地址! ,同时也相应的分配了对应的mm_struct进程地址空间(PCB中储存了该进程对应的进程地址空间的地址),也就是每个进程都认为自己独占内存资源 对于进程来说,进程控制块以及进程地址空间以及相应的资源 ,这些虚拟地址通过页表映射与物理内存建立联系 程序执行流程: 程序运行,进程被加载到CPU上,系统在内核为进程创建PCB记录进程属性,分配进程空间地址,由页表构建虚拟地址与物理地址的映射关系,程序查找或者修改数据会通过 PCB找到对应的进程地址空间,再由进程地址空间上的虚拟地址由页表找到物理空间上分配的数据 示图: 对于父子进程变量地址相同数据不同: 父进程创建子进程时,子进程以父进程为模板构建进程,代码数据父子共享
这里的地址实际上是虚拟地址(线性地址),Linux也有可能叫做逻辑地址。 我们可以感性地理解虚拟空间。 进程会认为自己是独占系统资源的,然而实际上并不是。 写时拷贝 上述的任何一方尝试写入,操作系统先进行数据拷贝,更改页表映射,然后再让进程进行修改的技术称为写时拷贝 进程地址空间上的地址从全0到全1按照正常的方式排列,所以是连续的地址,所以这个地址空间也被称为线性地址 ;对于磁盘程序内部的地址称为逻辑地址,在Linux下,虚拟地址到线性地址、逻辑地址是一样的,但在其他地方,区分比较明确, ---- 二、为什么 了解了进程地址空间是什么了以后,那为什么存在进程地址空间呢 ,所以保证了内存数据的安全性 地址空间的存在,可以更方便的进行进程和进程的数据代码的解耦,保证了进程独立性的特征 对于进程而言,都有独立的地址空间及页表,通过页表映射到不同的物理内存上,所以一个进程数据的改变不会影响到另一个进程 但是对于Linux而言,虚拟地址、线性地址、逻辑地址都是一样的。 ---- 三、怎么做 由操作系统管理进程地址空间。
个人网站、项目部署、开发环境、游戏服务器、图床、渲染训练等免费搭建教程,多款云服务器20元起。
文章目录 1.虚拟地址空间简介 2.虚拟地址空间布局 参考文献 1.虚拟地址空间简介 虚拟地址空间(Virtual Address Space)是每一个程序被加载运行起来后,操作系统为进程分配的虚拟内存 因为除了用户进程,操作系统会独占一部分虚拟内存空间,用户进程只能使用操作系统分配给进程的地址空间,如果用户进程访问未经允许的地址空间,则会被操作系统判为非法请求,结果就是程序被操作系统强制结束。 比如 Windows 下的“进程因非法操作需要关闭” 和 Linux 下的 “Segmentation fault”,一般都是由于进程访问了非法的内存地址。 对于 Linux,4GB 的虚拟地址空间的默认分配状态如下: 2.虚拟地址空间布局 C/C++程序为编译链接后生成可执行的二进制文件,由多个段组成,一般包含代码段、数据段和 BSS 段等。 在调用函数后,系统通常会清除栈上保存的信息。栈另外一个重要的特征是,它的地址空间“向下减少”,即当栈上保存的数据越多,栈的地址就越低。
在 Linux 系统中,采用了虚拟内存管理技术,事实上大多数现在操作系统都是如此! 在 Linux 系统中,每一个进程都在自己独立的地址空间中运行,在 32 位系统中,每个进程的逻辑地址空间均为 4GB,这 4GB 的内存空间按照 3:1 的比例进行分配,其中用户进程享有 3G 的空间 虚拟地址会通过硬件 MMU(内存管理单元)映射到实际的物理地址空间中,建立虚拟地址到物理地址的映射关系后,对虚拟地址的读写操作实际上就是对物理地址的读写操作,MMU 会将物理地址“翻译”为对应的物理地址 Linux 系统下,应用程序运行在一个虚拟地址空间中,所以程序中读写的内存地址对应也是虚拟地址,并不是真正的物理地址,譬如应用程序中读写 0x80800000 这个地址,实际上并不对应于硬件的 0x80800000 所有应用程序运行在自己的虚拟地址空间中,使得进程的虚拟地址空间和物理地址空间隔离开来,这样做带来了很多的优点: ⚫ 进程与进程、进程与内核相互隔离。
进程地址空间的隔离 是现代操作系统的一个显著特征。这也是区别于 “古代”操作系统 的显著特征。 进程地址空间隔离意味着进程P1无法以随意的方式访问进程P2的内存,除非这块内存被声明是共享的。 在操作系统中,家庭类似于虚拟地址空间,而房子就是页表。 邻居不能闯入你的房子,但特权管理机构只要理由充分,就可以进入普通人家的房子,touch这家人的东西。 对于操作系统而言,这就是内核可以做的事,内核可以访问任意进程的地址空间。 当然了,内核并不会无故私闯民宅,就像警察不会随意闯入别人家里一样。 但是,你可以让内核故意这么做,做点无赖的事情。 Linux的可玩性在于你可以自己动手,又可以让人代劳。比如,获取一个进程的虚拟地址的页表项指示的物理页面,就可以直接得到。 有这样的API吗? ---- 虚拟地址空间是每进程的,而物理地址空间则是所有进程共享的。换句话说,物理地址是全局的。
要查看一个进程的虚拟地址空间的内存布局,需要设置阻塞。如果没有设置阻塞,当./a.out按下去后,程序执行的速度非常快以至于来不及查看,所以需要设置阻塞。 /a.out &放在后台执行 3. ps -u查看进程id 4. cat /proc/进程id/maps 输出进程虚拟地址空间的布局
Linux可执行文件与进程的虚拟地址空间 一个可执行文件被执行的同时也伴随着一个新的进程的创建。 Linux会为这个进程创建一个新的虚拟地址空间,然后会读取可执行文件的文件头,建立虚拟地址空间与可执行文件的映射关系,然后将CPU的指令指针寄存器设置成可执行文件的入口地址,然后CPU就会从这里取指令执行 Proc目录下的进程虚拟地址空间布局 Linux在装载可执行文件的时候,会将这些segment映射到进程的地址空间中。映射的时候,这里面的segment会对应一个VMA。 Linux将进程虚拟地址空间中的一个段叫做虚拟内存区域(VMA)。在/proc目录下,可以查看一个进程的虚拟地址空间,通过命令 cat /proc/pid/maps ? segment映射到进程虚拟地址空间中的一个VMA中。
引言: 了解Linux环境下,进程的地址空间划分,对于我们理解Linux应用程序有很大的帮助,否则会被New与Malloc之类的指针操作弄的晕头转向,本文基于Linux内核讲述了Linux/ Unix线性地址空间的划分,为你答疑解惑。 从逻辑上来看,Unix程序的线性地址空间传统上被分为几个叫做段(segment)的区间。 一、正文段 包含程序的可执行代码。 二、已初始化数据段 包含已初始化的数据,包括所有静态成员变量和全局变量。现在能理解啥const类型的变量,不允许你更改了吧。 四、堆栈段 包含程序的堆栈,堆栈中有返回的地址,参数和被执行函数的局部变量。 五、总结 看到以上的内容,明白你的进程地址空间的结构了吧,全局变量在哪里?静态变量在哪里?局部变量在哪里?
虚拟地址:虚拟地址的偏移量部分加上段的基地址上就可以定位段中某个字节的位置,即形成线性地址空间中的地址。 当程序试图访问线性地址空间上的一个地址位置时,发生以下操作: if(数据在物理内存中) { 虚拟地址转换成物理地址 读数据 } else { if(数据在磁盘中) { 二、linux进程地址空间 由前面可得知,进程有4G的寻址空间,其中第一部分为“用户空间”,用来映射其整个进程空间(0x0000 0000-0xBFFF FFFF)即3G字节的虚拟地址;第二部分为“系统空间 程序路径:完整的绝对路径字符串如 “/home/simba/code/asm/simple” 环境变量:类似linux下的PATH,HOME等的环境变量,子进程会继承父进程的环境变量。 共享库和mmap内存映射区:比如很多程序都会用到的printf,函数共享库 printf.o 固定在某个物理内存位置上,让许多进程映射共享。
Linux上增加交换空间有两种方法: 严格的说,在Linux系统安装完后只有一种方法可以增加swap,那就是本文的第二种方法,至于第一种方法应该是安装系统时设置交换区。 交换空间的大小,与CPU密切相关,在i386系中,最多可以使用2GB的空间。 在系统启动后根据需要在2G的总容量下进行增减。 下面是运用swapfile增加交换空间的步骤: 涉及到的命令: free ---查看内存状态命令,可以显示memory,swap,buffer cache等的大小及使用状况; [root@www.linuxidc.com~]# dd if=/dev/zero of=/swapfile bs=1G count=5 dd: 写入"/swapfile" 出错: 设备上没有空间 (虽有这有提示但已启用成功了,以后要注意尽量先修改文件权限为0600) 至此增加交换空间的操作结束了,可以使用free命令查看swap空间大小是否发生变化; 注:swap空间增加的话可能要目录的磁盘空盘要足够
对该概念做一般概述之后,我将讨论命名空间框架所提供的基础设施。 命名空间概念 传统上,在Linux以及其他衍生的UNIX变体中,许多资源是全局管理的。 如果提供Web主机的供应商打算向用户提供Linux计算机的全部访问权限,包括root权限在内。传统上,这需要为每个用户准备一台计算机,代价太高。 请注意,Linux系统对简单形式的命名空间的支持已经有很长一段时间了,主要是chroot系统调用。该方法可以将进程限制到文件系统的某一部分,因而是一种简单的命名空间机制。 CLONE_NEWNET 网络命名空间,用于隔离网络资源(/proc/net、IP 地址、网卡、路由等)。后台进程可以运行在不同命名空间内的相同端口上,用户还可以虚拟出一块网卡。 一个container就是一个虚拟的运行环境,对container里的进程是透明的,它会以为自己是直接在一个系统上运行的。
进程的地址有三种,分别是虚拟地址(逻辑地址)、线性地址、物理地址。在分析之前先讲一下进程执行的时候,地址的解析过程。 在保护模式下,段寄存器保存的是段选择子,当进程被系统选中执行时,会把tss和ldt等信息加载到寄存器中,tss是保存进程上下文的,ldt是保存进程代码和数据段的首地址偏移以及权限等信息的。 tss信息中的idt索引首先从gdt找到进程idt 结构体数据的首地址,然后根据当前段的属性,比如代码段, 则从cs中取得选择子,系统从idt表中取得进程线性空间 的首地址、限长 接着计算一个在全局描述符GDT中的一个索引,这个索引是ldt选择子。后面会讲到。然后计算进程的代码和数据的线性地址首地址和限长,写到ldt的描述符中。接着复制页表,但是不分配物理地址。 最后根据tss中的cs和ip执行进程。这就是文章开头的过程。这就是linux0.11版本中进程地址管理的实现。下面是fork后的结构图。 ?
引言 上一篇文章中,我们介绍了内核调度的基本概念,知道了调度器设计中最核心的两个指标 -- 周转时间与响应时间: linux 操作系统的进程调度(上) -- 进程调度的基本概念 本文,我们就继续顺着上文的思路 SJF 算法的理想虽然很美好,但在实际系统执行过程中,却往往存在着两个致命的问题: 在进程执行过程中,新的任务随时都有可能到来,如果任务不是同时到来的,那么 SJF 算法事实上就退化成了 FCFS 算法 多级反馈队列 MLFQ 针对 RR 算法存在的问题,结合我们上一篇文章中介绍的 IO 密集型与 CPU 密集型进程的区别: IO 密集型:频繁 IO,但占用 CPU 的时间不多; CPU 密集型:进程执行过程中很少执行 从这三条原则,我们看出,操作系统必须在运行过程中区分一个进程究竟是 IO 密集型还是 CPU 密集型,并且在正确区分它们的基础上,需要增加优先级概念,从而让 IO 密集型进程更为优先和频繁地被分配到 CPU 结语 正是有了多级反馈队列算法,现代生产级操作系统中的进程调度器才得以真正建立起来。 下一篇文章,我们就来深入 linux,来了解具体的 linux 进程调度器的发展历史和实现机制,敬请期待。
方法1:使用iotop工具 这是一个python脚本工具,使用方法如:iotop -o 方法2:使用工具dmesg 使用dmesg之前,需要先开启内核的IO监控: echo 1 >/proc /sys/vm/block_dump或sysctl vm.block_dump=1 然后可以使用如下命令查看IO最重的前10个进程: dmesg |awk -F: '{print $1}'| 1.74 6.75 23.47 200.18 11.73 100.09 26.33 0.10 12.25 5.73 4.87 找“await”值最大的设备 (Device),如上的结果即为sda。 然后使用mount找到sda挂载点,再使用fuser命令查看哪些进程在访问,如: # fuser -vm /data
,想象一下,你移动了一下鼠标,CPU 由于被 CPU 密集型进程占用着,而让你的鼠标在屏幕上一顿一顿地移动,这显然太过于糟糕。 在 Linux 操作系统中,系统会为每个进程打一个分,这个分就是 PR 值,它是 Priority 的前两个字母。 通过 PR 值的范围,linux 换分出了两类进程: 实时进程 -- PR 值在 0 到 99 之间,PR 值越大,优先级越高; 普通进程 -- PR 值在 100 到 139 之间,PR 值越小,优先级越高 但有时,用户可能会不认可操作系统的优先级数值,而是想要去手动调整进程的优先级。此时,如果让用户直接干预 PR 值,那风险就显得很大。Linux 为用户层设计了一个 Nice 值,翻译为“谦让值”。 结语 本文,我们从操作系统的整体层面,了解了操作系统进程调度的基本概念和设计思想,但我们尚未触及核心部分,到底 linux 系统中的调度器是如何设计的,又有着怎样的历史沿革,出现了哪些算法?
三.进程与JVM内存空间 JVM本质就是一个进程,因此其内存空间(也称之为运行时数据区,注意与JMM的区别)也有进程的一般特点。深入浅出 Java 中 JVM 内存管理,这篇参考下。 JVM的堆区和普通进程的差别是最大的,下面具体详细说明: 首先是永久代。永久代本质上是Java程序的代码区和数据区。 新生代和老年代才是Java程序真正使用的堆空间,主要用于内存对象的存储;但是其管理方式和普通进程有本质的区别。 普通进程在运行时给内存对象分配空间时,比如C++执行new操作时,会触发一次分配内存空间的系统调用,由操作系统的线程根据对象的大小分配好空间后返 回;同时,程序释放对象时,比如C++执行delete操作时 Linux和Java NIO在内核内存上开辟空间给程序使用,主要是减少不要的复制,以减少IO操作系统调用的开销。
默认情况下,du 列出了当前目录中使用的磁盘空间,以及每个子目录的大小。 $ du12 ./.backups60 . 显示相同的信息(48KB 加 12KB 是 60KB),但每个目录被独立处理。 查看文件的修改时间 当查看文件以找出占用空间的内容时,查看文件最后一次被修改的时间是很有用的。一年内没有使用过的文件可以考虑归档,特别是当你的空间快用完时。 为文件大小设置一个阈值 当为了磁盘空间而查看文件时,你可能只关心较大的文件。你可以通过 --threshold(简写 -t)选项为文件大小设置一个阈值。 2020-04-11 13:10 /home/tux/Footage/waterfall.mp48.5G 2021-07-14 13:55 /home/tux/Footage/ 查看可用磁盘空间
在 Linux 上查找可用磁盘空间的最简单的方法是使用 df 命令 。df 命令从字面意思上代表着 磁盘可用空间(disk free),很明显,它将向你显示在 Linux 系统上的可用磁盘空间。 我将介绍一些关于在 Linux 中检查可用磁盘空间的东西。我也将为桌面 Linux 用户展示 GUI 方法。 方法 1: 使用 df 命令来检查在 Linux 中的可用磁盘空间(并理解它的输出) 当你使用 df 命令来检查磁盘空间时,它将显示一组“文件系统”,包括它们的大小、使用的空间和可用的空间。 image.png 你可以使用 lsblk 命令来查看在你系统上的所有磁盘和分区。 image.png 在你有了磁盘分区名称后,你可以用这种方式来挂载它: sudo mount /dev/sdb2 /mnt 我希望这种方法能够给你提供一个在 Linux 上检查硬盘驱动器空间的好主意。
无论你有多少存储空间,它总有可能被填满。在大多数个人设备上,磁盘被照片、视频和音乐填满,但在服务器上,由于用户账户和日志文件数据,空间减少是很正常的。 无论你是负责管理一个多用户系统,还是只负责自己的笔记本电脑,你都可以用 du 命令检查磁盘的使用情况。 默认情况下,du 列出了当前目录中使用的磁盘空间,以及每个子目录的大小。 查看文件的修改时间 当查看文件以找出占用空间的内容时,查看文件最后一次被修改的时间是很有用的。一年内没有使用过的文件可以考虑归档,特别是当你的空间快用完时。 为文件大小设置一个阈值 当为了磁盘空间而查看文件时,你可能只关心较大的文件。你可以通过 --threshold(简写 -t)选项为文件大小设置一个阈值。 如需获得一个驱动器上可用磁盘空间的摘要,请阅读我们关于 df 命令的文章。
云端获取和启用云服务器,并实时扩展或缩减云计算资源。云服务器 支持按实际使用的资源计费,可以为您节约计算成本。 腾讯云服务器(CVM)为您提供安全可靠的弹性云计算服务。只需几分钟,您就可以在云端获取和启用云服务器,并实时扩展或缩减云计算资源。云服务器 支持按实际使用的资源计费,可以为您节约计算成本。
扫码关注腾讯云开发者
领取腾讯云代金券