趣谈Linux操作系统学习笔记-内存管理(20讲)
计算机进行计算
包括2方面:
1) 进程和线程对cpu的使用
2) 内存管理
独享内存空间的原理
每个进程都有自己独立的内存空间,如果直接使用物理空间,多个程序同时执行会有占用冲突。所以程序使用虚拟地址,系统负责把虚拟地址和物理地址映射起来
1、会议室和物理内存的关系
和会议室一样,内存都被分成一块块儿的,都编号了号,例如3F-10就是三楼十号会议室、内存页有这样一个地址。这个地址是实实在在的地址,通过这个地址我们就能够定位到物理内存地址
2、会产生什么问题呢?
3F-10打开三个相同的程序,都执行到某一步,比方说,打开三个计算机器,用户在这三个程序的界面、上分别输入10、100、1000,如果内存中的这个位置只能保存一个数,
那应该保存那个呢?这不就冲突了吗?
3、谁也不能直接访问物理地址
每个项目的物理地址对于进程不可见,谁也不能直接访问物理地址,操作系统会给进程分配一个虚拟地址。所有进程看到的这个地址都是一样的,里面的内存都是从0开始编号
4、在程序里面,指令写入的地址是虚拟地址
例如,位置我10M的内存区域,操作系统会提供一种机制,将不同的进程的虚拟地址和不同的物理地址映射起来
当程序要访问虚拟地址的时候,由内核的数据结构转换,转换成不同的物理地址,这样不同的进程运行的是时候,写入的是不同的物理地址这样就不会冲突了
规划内存管理:
操作系统的内存管理包括3个方面:
一. 物理内存的管理, 相当于会议室管理员管理会议室
二. 虚拟地址的管理,也即在项目组的视角,会议室的虚拟地址应该如何组织。
三. 物理地址和虚拟地址做好映射,也即会议室管理员如果管理映射表。
举个栗子:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int max_length = 128; 5 6 char * generate(int length){ 7 int i; 8 char * buffer = (char*) malloc (length+1); 9 if (buffer == NULL) 10 return NULL; 11 for (i=0; i<length; i++){ 12 buffer[i]=rand()%26+'a'; 13 } 14 buffer[length]='\0'; 15 return buffer; 16 } 17 18 int main(int argc, char *argv[]) 19 { 20 int num; 21 char * buffer; 22 23 printf ("Input the string length : "); 24 scanf ("%d", &num); 25 26 if(num > max_length){ 27 num = max_length; 28 } 29 30 buffer = generate(num); 31 32 printf ("Random string is: %s\n",buffer); 33 free (buffer); 34 35 return 0; 36 }
总结一下
这个简单的程序在使用内存时的几种方式:
1)代码需要放在内存里面;
2)全局变量,例如 max_length;
3)常量字符串"Input the string length : ";
4)函数栈,例如局部变量 num 是作为参数传给 generate 函数的,这里面涉及了函数调用,局部变量,函数参数等都是保存在函数栈上面的;
5)堆,malloc 分配的内存在堆里面;
6)这里面涉及对 glibc 的调用,所以 glibc 的代码是以 so 文件的形式存在的,也需要放在内存里面
内核部分还需要分配内存:
1)内核的代码要在内存里面;
2)内核中也有全局变量;
3)每个进程都要有一个 task_struct;
4)每个进程还有一个内核栈;
5)在内核里面也有动态分配的内存;
6)虚拟内存和物理内存的映射
内存的排列
1)内存先分为用户态空间和内核态空间,用户态占用0到29号,内核态占用30到39号。
2) 用户态从0号到29号,依次是text segement(存放二进制可执行代码的位置段),data segment(存放初始化的静态常量),bss segment(存放未初始化的静态变量),heap(动态分配内存的区域),接下来是Memory Mapping segment,把文件映射进内存使用。接下来是栈地址段,
3) 内核态是共享的,无论哪个进程进入到内核,看到的空间和进程列表都是一样的,如果要访问公共资源需要加锁。