实验 通过命令和代码初步感受存储管理【操作系统】

简介: 实验 通过命令和代码初步感受存储管理【操作系统】

通过命令和代码初步感受存储管理

1.什么是存储器的层次结构,如何通过命令进行查看?

大家所熟知的是内存(RAM)和外存,尽管内存比外存速度快很多,但还是无法与CPU的速度匹配,因此CPU内部就需要更快的存储装置,这就是高速缓存(Cache)。从图中看出,高速缓存并不属于内存,而属于CPU的组成部分。另外,还有内存管理单元MMU(Memory Management Unit),这是为了支持虚拟内存管理而专门设置的硬件机制,也属于CPU的管辖范围。可以看出,为了支持内存管理,CPU使出了浑身解数,CPU和内存的关联更加紧密。

那么如何查看CPU中的Cache ?

我们可以通过lscpu命令查看CPU内部的缓存,




从输出结果看,在x86机器上,
L1d 和L1i cache,为一级数据和指令缓存,大小都为32k,
L2,L3Cache为二级和三级缓存,分别是521K,8192K,大小各不同。

可以通过free命令查看内存的情况。

free命令查看内存
Mem 行(第二行)是内存的使用情况。
Swap 行(第三行)是交换空间的使用情况。
total 列显示系统总的可用物理内存和交换空间大小。
used 列显示已经被使用的物理内存和交换空间。
free 列显示还有多少物理内存和交换空间可用使用。
shared 列显示被共享使用的物理内存大小。
buff/cache 列显示被 buffer 和 cache 使用的物理内存大小。
available 列显示还可以被应用程序使用的物理内存大小。

2. 如何编译、链接、装载并执行一个程序?




3. Linux中进程地址空间是怎样的?


一个程序编译链接后形成可执行文件,可执行文件加载执行后,就摇身一变成为进程了,进程地址空间如图最右边所示。除了代码区,初始化数据区,BSS区外,还有堆、栈和共享库等,其中,栈中存放存放函数的参数值、返回值、局部变量等,而堆是用来为用户程序中的malloc()等分配内存的,printf函数存放在共享库中。

4. 如何编写代码 感受自己写的代码放在进程地址空间的哪些段中?

代码

请敲如下代码:

#include  <stdio.h>
#include  <stdlib.h>
#include  <unistd.h>
int A;        //全局未初始化变量
int B=0;      //全局初始化为0的变量
int C=2;      //全局初始化变量
static int D;     //全局静态未初始化变量
static int E=0;   //全局静态初始化为0的变量
static int F=4;   //全局静态初始化变量
const  int G=5;   //全局常量
const char H=6; 
int main(void){
  int a;       //局部未初始化变量
  int b=0;           //局部初始化为0的变量
  int c=2;           //局部初始化变量
  static  int d;     //局部静态未初始化变量
  static  int e=0;      //局部静态初始化为0的变量
  static int f=4;       //局部静态初始化变量
  const int g=5;        //局部常量
  char  char1[] = "abcde";//局部字符串数组
  char  *cptr="123456";   //p在栈上,123456在常量区
  int *heap=malloc(sizeof(int)*4);//堆
  printf("PID is :%d\n\n",  getpid());
  printf("int A           A_addr = %p\n",&A);
  printf("int B=0         B_addr = %p\n",&B);
  printf("int C=2         C_addr = %p\n",&C);
  printf("static int D        D_addr = %p\n",&D);
  printf("static int E=0      E_addr = %p\n",&E);
  printf("static int F=4      D_addr = %p\n",&F);
  printf("const int G=5      G_addr = %p\n",&G);
  printf("const char H=6      H_addr = %p\n",&H); 
  printf("\n");
  printf("int a           a_addr = %p\n",&a);
  printf("int b=0         b_addr = %p\n",&b);
  printf("int c=2         c_addr = %p\n",&c);
  printf("static int d        d_addr = %p\n",&d);
  printf("static int e=0      e_addr = %p\n",&e);
  printf("static int f=4      f_addr = %p\n",&f);
  printf("const int g=5      g_addr = %p\n",&g);
  printf("\n");
  printf("char char1[] = 'abcde'\t\t\tchar1_addr = %p\n",char1);
  printf("char char1[] = 'abcde'\t\t\t&char1_addr = %p\n",&char1);
  printf("char *cptr  = '1'\t\t\tcptr_addr = %p\n",&cptr);
  printf("value of the cptr\t\t\tcptr_value = 0x%p\n",cptr);
  printf("value of the %p\t\t\tvalue_0x%p = %d\n",cptr,cptr,*cptr);
  printf("int* heap = malloc(sizeof(int)*4)\theap__addr = %p\n",heap);
  printf("int* heap = malloc(sizeof(int)*4)\t&heap__addr = %p\n",&heap);
  pause();
  //程序结束运行之后再回收堆内存,方便观案堆的地址 
  free(heap);
  return 0;
}

编译并运行该程序:


仔细分析你的运行结果,你发现什么?

结果





你也可以用size命令进行查看。

分析

进程地址空间的段说明

在图片下搜索关键词

32位4GLinux虚拟地址空间布局






【Linux】Linux下4G虚拟地址空间布局

简述代码中关于.data、.bss、.rodata、.text段的意义

kernel space 内核空间

Undefined Region

Stack

Memmory Mapping Region 共享库
heap

bss段(Block(b) Started(s) by Symbol(s)):即用来存储一些未被初始化的全局变量和静态变量的内存区域,一般在初始化时bss段部分将会清零,属于静态内存分配,即程序一开始就将其清零了。

例:



#include<xxx.h>
int bss_value1;//全局的未被初始化的变量,处于bss段
static void *bss_value2 = NULL;//全局的指针变量,处于bss段
int main()
{
//…;
return 0;
}

注意:BSS段不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行时被有效的清零。并不给该段的数据分配空间,只是记录数据所需空间的大小。不占用可执行文件的空间,BSS段在应用程序的二进制映像文件中并不存在。

特点:可读写。
data段:又称为数据段,通常是指用来存放程序中已被初始化的全局变量,常量,静态变量的一块内存区域。也就是我们通常说的静态存储区。

例:

#include<xxx.h>
int bss_value1=5;//全局的被初始化的变量,处于data段
int main()
{
…;
return 0;
}

注意:data段为数据分配空间,数据保存在目标文件中。

特点:可读写。
text段 (textsegment):通常指用来存放程序执行代码的一块内存区域,这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。
在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

特点:只读

rodata段:该段也叫常量区,用于存放常量数据,ro就是read only(只读)。

例:

#include<xxx.h>
//int bss_value1=5;//全局的被初始化的变量,处于data段
//const int bss_value1=5;//加上const变为只读的常量,处于rodata段
int main()
{
//…;
return 0;
}

注意:并不是所有的常量都放在常量数据段,特殊情况如下

(1):有些立即数与指令编译在一起放在代码段

(2):对于字符串常量,编译器会自动去掉重复的字符串,保证一个字符串在一个可执行文件(EXE/SO)中只存在一份拷贝。
c语言中const修饰的局部变量和全局变量存放在哪个区域

分析

以下皆是个人见解

int A;        //全局未初始化变量      bss
int B=0;      //全局初始化为0的变量    bss
int C=2;      //全局初始化变量       data
static int D;     //全局静态未初始化变量   bss
static int E=0;   //全局静态初始化为0的变量    bss
static int F=4;   //全局静态初始化变量         data
const  int G=5;   //全局常量                   rodata
const char H=6;                                 rodata
int main(void){
  int a;       //局部未初始化变量            stack
  int b=0;           //局部初始化为0的变量   stack
  int c=2;           //局部初始化变量        stack
  static  int d;     //局部静态未初始化变量     bss
  static  int e=0;      //局部静态初始化为0的变量  bss
  static int f=4;       //局部静态初始化变量   data
  const int g=5;        //局部常量            stack
  char  char1[] = "abcde";//局部字符串数组     stack
  char  *cptr="123456";   //p在栈上,123456在常量区
  int *heap=malloc(sizeof(int)*4);//堆
  //...
}




5. 如何查看编译、链接后的汇编代码?

通过objdump命令

1) 查看编译后的汇编代码

 objdump -d test.o -Mintel //intel 汇编格式

2)查看链接后的汇编代码

 objdump -d test -Mintel //intel 汇编格式

进行对比,说明编译到底做了什么,链接做了什么?

相关文章
|
28天前
|
算法 搜索推荐 开发工具
探索代码的奥秘:技术感悟与实践探索操作系统的心脏:内核
【5月更文挑战第31天】在数字世界的编织中,每一行代码都承载着创造者的智慧和汗水。本文将带你深入编程的核心,揭示那些隐藏在日常开发实践中的技术真谛。从算法的精妙到系统的架构,我们将一同探讨如何通过技术提升效率,解决问题,并在这个过程中获得个人成长。 【5月更文挑战第31天】本文深入剖析了操作系统的核心组件——内核,探讨了其设计哲学、功能职责以及在现代计算环境中的重要性。通过分析内核的工作原理和它如何与硬件、软件交互,我们将揭示这个隐藏在用户界面背后的力量之源。
|
22天前
|
运维 安全 Unix
Linux操作系统 , 常用命令
Linux操作系统 , 常用命令
|
15天前
|
Linux Shell 程序员
【Linux操作系统】命令的运行原理
【Linux操作系统】命令的运行原理
|
1月前
|
存储 缓存 程序员
手写操作系统(2)——代码是怎么运行的?(下)
手写操作系统(2)——代码是怎么运行的?
23 1
|
1月前
|
存储
手写操作系统(2)——代码是怎么运行的?(中)
手写操作系统(2)——代码是怎么运行的?
18 1
|
1月前
【操作系统】实验九 写一个设备驱动程序
【操作系统】实验九 写一个设备驱动程序
22 1
|
1月前
【操作系统】实验八 proc文件系统
【操作系统】实验八 proc文件系统
15 1
|
1月前
|
Linux API
【操作系统】实验七 显示进程列表
【操作系统】实验七 显示进程列表
19 1
|
1月前
|
存储 机器学习/深度学习 算法
【操作系统】实验六 分析源代码
【操作系统】实验六 分析源代码
24 1
|
1月前
|
Linux 编译器 API
【操作系统】实验五 添加内核模块
【操作系统】实验五 添加内核模块
25 1