Linux对内存结构的描述

1.查看Linux程序运行时状态

Linux在运行可执行文件时,该状态信息全部在/porc/${PID}中。

proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。

用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息(如进程),是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。

例如,运行下面的简单程序,查看:

//  Day01/1.1/TestDemo01.c

#include

#include

int main(){

int a=40;

int b;

printf("&a=%p\n",&a);

printf("&b=%p\n",&b);

printf("PID=%d\n",getpid());//getpid为获取本程序运行时的进程号,相关知识后续章节

while(1);//禁止程序运行完毕退出,否则/proc/${PID}中没有任何数据

}

除了使用getpid()函数外,还可以使用ps  aue查看当前状态下,所有的进程信息。

进入对应的pid文件夹,程序运行的所有动态信息都在,程序一解锁,该pid文件夹中所有的信息都被删除了。

程序运行如下:(每台计算机中的PID都几乎不可能是相同的)

进入/proc/${PID}中查看相关内容:

先来简单补充下/proc文件夹的相关知识:

Linux内核提供了一种通过/proc文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。

用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。下面列出的这些文件或子文件夹,并不是都是在你的系统中存在,这取决于你的内核配置和装载的模块。另外,在/proc下还有三个很重要的目录:net,scsi和sys。Sys目录是可写的,可以通过它来访问或修改内核的参数,而net和scsi则依赖于内核配置。例如,如果系统不支持scsi,则scsi目录不存在。

除了以上介绍的这些,还有的是一些以数字命名的目录,它们是进程目录。系统中当前运行的每一个进程都有对应的一个目录在/proc下,以进程的PID号为目录名,它们是读取进程信息的接口。而self目录则是读取进程本身的信息接口,是一个link。

在proc文件系统中,主要包含三大类内容,进程相关部分,系统信息部分,以及系统子系统部分。procfs包含的内容:

*进程相关部分(只读)

这部分文件都是以数字为名的子目录,这个数字就是相关进程的进程ID,需要注意的是procfs中进程子系统部分的一个特殊点,就是/proc/self,它是指向当前执行进程的符号连接,或者说--是指向未来你将要执行指令。下面是进程文件中的某些内容说明:

cmdline——执行进程的命令行参数

cpu——在SMP系统中近程最后的执行CPU

fd——到当前工作目录的符号链接

mem——进程内存空间

root——连接到进程执行时的/ (root)目录

stat——进程状态

statm——进程内存状态信息

exe——链接到进程对应的源可执行文件,指向这个执行程序

environ——当前程序运行的环境参数和变量

cwd——到当前工作目录的符号链接

fd——到当前工作目录的符号链接

?maps——进程内存映射,包含进程执行空间以及动态链接库信息,保存当前程序运行的所有内存结构,可以很清晰的看见该程序进程的内存分配情况:

p表示私有的,保护的。

从0076b00——0095300理论上是1G的空间,程序映射到内核上的动态库和共享库。

stack编译期间变量空间放到全局栈里面

*内核信息部分(只读)

这部分文件同样处于/proc的顶层目录,不过它们大部分都是常规、只读的文本文件,可以直接用cat查看信息。作为系统内核执行体的抽象,我们也可以把它看作内核"进程"的信息部分,当然虽然并不存在这个进程实体。

*内核各子系统相关部分(部分可调)

这部分是系统内核参数调整的重头戏,在procfs中,除去上面所述的两部分内容外,还有很大一部分信息文件被存放在了一些并非以数字命名的特殊目录中,这些目录下的信息就是内核各个重要子系统的信息和可调参数,主要有:

bus总线信息(只读)

drivers驱动信息(只读)

fs文件系统特别信息(只读)

ide IDE接口信息(只读)

irq IRQ信息(只读)

net网络子系统信息(只读)

scsi SCSI系统信息(只读)

sysvipc IPC子系统信息(只读)

tty tty子系统信息(只读)

sys系统内核可调参数(可调)

作为Linux系统内核参数的抽象文件接口,Linux内核的大部分默认可调参数都被放在了/proc/sys目录下,这些参数都以常规文件的形式体现,并且可以用echo/cat等文件操作命令进行调整,调整的效果是即时的,并且在系统运行的整个生命周期之间都有效(知道再次改变它们或者系统重启)。

当然Linux也提供了另外一种途径sysctl来调整这些参数,sysctl是从BSD系统继承而来的一种系统参数动态调整方法,sysctl的使用更为简单,并且可以使用/etc/sysctl.conf保存配置以在下次启动时自动加载这些设置。

在本章节需要重点研究/proc/${PID}/maps文件中的,内存分配情况。

2程序变量内存空间关系

下面来分析下函数中各个变量的分布:

1.进程内存结构

每一个进程都有以下区域:

代码段:代码段是用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存种的镜像。代码段需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作——它是不可写的,拥有可执行权限。

数据段:数据段用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配[1]的变量和全局变量。

BSS段:BSS段包含了程序中未初始化全局变量,这些变量根据不同的c标准都有相应的初始值。

堆(heap):堆是用于存放进程运行中被动态分配的内存段,它大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

栈:栈是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味这在数据段中存放变量)。除此以外在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也回被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上将我们可以把堆栈看成一个临时数据寄存、交换的内存区。

结构如下:

Linux从两个方面优化:

首先,这个段是用来存放没有初始化的数据,所以连接器实际并不会将特殊的值存储在对象文件, 这样可以减少二进制代码文件的小。

其次,当这个段被加载到内存时,内存只需要简单的根据写时复制的原则将它们 映射到一个全是0的页上,这样非常高效的设置了初值。

2.理解程序的变量与内存空间的关系

来看下面的示例:

// Day01/1.1/Varmem.c

#include

#include

#include

int add(int a,int b){

return a+b;

}

int a1=1;

static int a2=2;

const int a3=3;

main(){

int b1=4;

static b2=5;

const b3=6;

int *p1=malloc(4);

printf("a1:%p\n",&a1);

printf("a2:%p\n",&a2);

printf("a3:%p\n",&a3);

printf("b1:%p\n",&b1);

printf("b2:%p\n",&b2);

printf("b3:%p\n",&b3);

printf("p1:%p\n",p1);

printf("main:%p\n",main);

printf("add:%p\n",add);

printf("%d\n",getpid());

while(1);

}

运行结果:

仔细对比maps的内容就会明确的看出各个变量在内存中的分布情况:

C语言中内存存储区变量的分配:

1.栈-由编译器自动分配释放

2.堆-一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收

3.全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。-程序结束释放

4.另外还有一个专门放常量的地方。-程序结束释放

在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。

在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。

另外,函数中的"adgfdf"这样的字符串存放在常量区。比如:

int a = 0; //全局初始化区

char *p1; //全局未初始化区

void main()

{

int b; //栈

char s[] = "abc"; //栈

char *p2; //栈

char *p3 = "123456"; //123456{post.content}在常量区,p3在栈上

static int c = 0; //全局(静态)初始化区

p1 = (char *)malloc(10); //分配得来得10字节的区域在堆区

p2 = (char *)malloc(20); //分配得来得20字节的区域在堆区

strcpy(p1, "123456");

//123456{post.content}放在常量区,编译器可能会将它与p3所指向的"123456"优化成一块

}

在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区

1.栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。

2.堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

3.自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。

4.全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

5.常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)。

简单的总结下变量内存分配的特点和修饰符对变量内存分配的影响:

1、变量的内存分配方式有三种:

1)从静态存储区(属于数据段)域分配

针对例如全局变量,static变量,程序在编译时编译器就已对其分配好内存地址,这块内存在程序的整个运行期间都存在(这些变量的值在程序运行期间一致存在并且在程序加载时将其load进静态存储区)。

2)从栈上分配

针对局部变量(包括参数),在每次调用函数时,系统会动态为局部变量在栈中重新分配内存空间,变量值会被重新初始化成指定值或者随机值,在函数调用后这些局部变量占有的内存空间会被自动释放。

注:编译器在编译时会对局部变量分配一个内存地址(若变量被赋值初始化),但是在程序运行每次函数被调用时系统还是会动态分配一个内存地址给局部变量。

3)从堆上分配或称动态内存分配

由程序员调用malloc等函数可以向系统申请任意指定大小的内存,并由程序员自己调用free等函数来释放内存,动态分配内存的生命期由程序员决定,使用非常灵活,但问题也最多。

2、变量的存储类型

1) auto:属于栈上分配内存,默认不会初始化。

2) static(分为局部和全局静态变量):属于静态存储区分配内存,默认会初始化并仅初始化一次。

3) extern(非静态全局变量):同上

4) register:存放在寄存器中,只能是局部变量不能是全局变量并且不能加static修饰,默认不会初始化。

注:

*静态局部变量作用域限于一个函数,静态全局变量限于一个文件

*非静态全局变量作用域不限于一个文件,可以扩展到其它文件

*存储类型决定了一个变量的生命周期和作用域

linux文件夹前的描述,Linux对内存结构的描述相关推荐

  1. linux文件夹加密访问,技术|Linux系统上用encfs创建和管理加密文件夹

    如果你想使你计算机上的某些信息免于被窥视的话,可以看看这篇文字.保护信息的一种方法就是加密你的home目录,但是一旦你登录系统后,你的home目录下的信息将暴露于外.过去,我已经写过关于怎样在你的系统 ...

  2. linux 文件夹换所属用户,Linux中账号管理之权限管理(下)

    linux中的账号管理我们在前面两张已经介绍了一些用户和组的相关概念,常用的配置文件,命令的使用.现在我们来看看账号管理中最傲娇的部分就是我们的权限管理. 一.简单介绍权限的概念 以install.l ...

  3. mac同步linux文件夹在哪里设置,Linux和Mac上的一些特殊文件将不再同步

    近日有用户报告, Mac/Linux上创建的某些文件, 无法成功同步到Windows平台上. 我们对这个问题进行了修正.  这个修正可能会影响到Linux和Mac用户中的极少数, 大概为数百位用户. ...

  4. linux文件夹分配用户权限,linux权限设置(开放某个文件夹给指定用户)

    问题背景: 今天想把自己的数据集开放给同事a,只允许其读,不允许写. 操作: step1: 查看该文件夹属于哪一个用户,哪一个组 ls 文件夹 -l step2: usermod -a -G 指定文件 ...

  5. linux 文件夹换所属用户,linux 如何修改文件夹所属用户名和用户组

    有一次魏艾斯博客新建了一个文件夹,把网站文件全都放了进去,后来发现 ftp 无法上传文件了,总提示上传失败.记得https://www.vpsss.net/252.html中提到了 ftp 无法正常上 ...

  6. linux 文件夹换所属用户,linux普通用户su root切换提示没有文件或目录的解决方法...

    1. 首先进入单用户模式: 1). ubuntu : 上述情况可以在grub界面选择第二项修复,但没有grub可以参考: 1.重启ubuntu,随即长按shirft进入grub菜单: 2.选择reco ...

  7. win10查看linux文件夹,Win10系统访问Linux子系统中文件的教程

    在19H1(目前处于Insider Preview阶段,预计4月份正式推送)中,微软为适用于Linux的Windows子系统带来了一项有趣的功能,这项功能允许用户从Windows 10访问Linux子 ...

  8. linux文件夹重命名busy,Linux下执行程序出现 Text file busy 提示时的解决方法

    使用 fuser xxx 命令查看制定的文件被哪个进程占用,然后关闭该进程,则解决问题. 备注: 如果 xxx 命令是在普通用root 下开启, 而在普通用户下使用:fuser xxx 是没有结果的 ...

  9. linux du命令 前多少个,Linux du命令查看文件夹大小并按降序排列

    1. df -lh 2. du -s /usr/* | sort -rn 这是按字节排序 3. du -sh /usr/* | sort -rn 这是按兆(M)来排序 4.选出排在前面的10个 du ...

最新文章

  1. 从pfx里面 解析出公私钥
  2. python怎么换行继续写脚本_用Python实现换行符转换的脚本的教程
  3. Core Java 第三章 Java基本的程序设计结构
  4. 【OS学习笔记】二十八 保护模式八:任务切换对应的汇编代码之内核代码
  5. Feature Engineering 特征工程 1. Baseline Model
  6. [导入]ASP常用函数:getIMG()
  7. 连载08:软件体系设计新方向:数学抽象、设计模式、系统架构与方案设计(简化版)(袁晓河著)...
  8. 开课吧Java课堂:什么是ArrayList类
  9. 分享两款迷你FTP服务器
  10. html5学习笔记(progress)
  11. ubuntu shell 直接输入密码
  12. java text类型转换_java语言实现Text格式转换成pdf文件
  13. charles破解版下载地址及其使用方法
  14. 坚果pro2刷回官方_坚果Pro2刷机教程刷TWRP面具详细步骤_软件开发_IT综合服务
  15. 《鬼武者3》全攻略宝典
  16. 用资源管理器打开ftp站点跳转浏览器解决方法
  17. F.grid_sample
  18. 4.2 人工智能产业岗位分布
  19. 鼠标使用板载内存和使用计算机上,鼠标怎么选?教你选择适合自己的游戏鼠标。...
  20. centos 7, 8 的区别

热门文章

  1. 四.MongoDB 概念解析
  2. 大数据搜索:Python编码实战
  3. java识别文件类型_在Java中识别文件类型
  4. php smtp 超时,SMTP错误:无法连接到服务器:连接超时(110)与PHPMailer和Outlook SMTP
  5. 模拟电路基础秦世才_模拟电子技术基础碎片化-晶体管及放大电路基础
  6. mysql 去除括号_MySQL语句批量去除括号及内容
  7. 信阳农林技术学院经纬度_信阳农林学院全景-360度,720度,高清全景地图-expoon网展...
  8. framebuffer结构体分析
  9. 编辑按钮 php,自定义百度编辑器菜单按钮
  10. 网络口协商_以太网端口协商解析