意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

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

来源:恒创科技 编辑:恒创科技编辑部
2022-09-22 00:25:00


实验 通过命令和代码初步感受存储管理【操作系统】​​通过命令和代码初步感受存储管理​​​​1.什么是存储器的层次结构,如何通过命令进行查看?​​​​2. 如何编译、链接、装载并执行一个程序?​​​​3. Linux中进程地址空间是怎样的?​​​​4. 如何编写代码 感受自己写的代码放在进程地址空间的哪些段中?​​​​代码​​​​结果​​​​分析​​​​进程地址空间的段说明​​​​分析​​​​5. 如何查看编译、链接后的汇编代码?​​通过命令和代码初步感受存储管理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. 如何编译、链接、装载并执行一个程序?

实验 通过命令和代码初步感受存储管理【操作系统】_静态初始化_02

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

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

一个程序编译链接后形成可执行文件,可执行文件加载执行后,就摇身一变成为进程了,进程地址空间如图最右边所示。除了代码区,初始化数据区,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;
}

编译并运行该程序:

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

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

结果

实验 通过命令和代码初步感受存储管理【操作系统】_静态初始化_05

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

分析进程地址空间的段说明

在图片下搜索关键词

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

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

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


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

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

​​简述代码中关于.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);//堆
//...
}

实验 通过命令和代码初步感受存储管理【操作系统】_静态初始化_09

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

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

通过objdump命令

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

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

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

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

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


上一篇: 租用美国服务器:潜在的风险与应对策略。 下一篇: MongoDB 5.0 扩展开源文档数据库操作