Linux系统的内存管理
虚拟内存
-----以下都是32位系统为前提-----
为什么要设置虚拟内存?
由于物理内存地址往往不够大,一个进程便需要占用到大量的内存,但是我们不可能
只运行一个或几个进程,所以需要创建虚拟地址空间来拓展进程对内存的使用。
由于要遵守这个规则,必须了解虚拟地址空间内部有些什么,如何工作的
1、因为操作系统要求安全性,它不允许进程在运行时直接访问内核,进程想要访问
操作系统必须通过操作系统做中转。
2、进程之间互相独立,当需要跨进程通信时,必须调用操作系统创建一个共享的文
件(因为linux操作系统内一切皆文件),通过一方写入、一方读取完成两个进程之间通
信。
3、我们每个进程在运行的时候有独立的4G字节的虚拟地址空间,进程只能访问虚拟
地址空间,无法直接访问物理地址。4G虚拟地址空间:0~3G:用户空间;3~4G:内核
空间;只有一张独立唯一的init_mm表与内存映射,所有进程共用它
注意:访问了没有映射过、没有权限的虚拟内存地址会产生段错误(非法访问)
虚拟地址空间是怎么生成的:
虚拟地址空间是通过操作系统软件、MMU(内存管理单元)中的地址翻译硬件
和一个存放在物理内存中叫`页表`的数据结构工作的。页表就是记录了虚拟页和物
理页映射关系的一种数据结构。每次地址翻译硬件将一个虚拟地址转换为物理地址时
,都需要读取页表。
[这篇文章详细讲了这些概念](https://blog.csdn.net/csdn_gjx/article/details/73139334)
进程映像
进程在内存空间中分布的情况叫进程映像。下面是它们在内存中的存储表(从
低地址到高地址):
1、代码段/制度段:二进制指令、字符串字面值、具有const且被初始化过的全局
变量静态变量
2、数据段:没有const属性的被初始化过的全局变量和静态变量
3、BSS段:没有初始化过的全局变量和静态变量,进程一旦加载成功就会把这段
内存清理为0
4、堆区:动态的分配、管理内存,需要程序员操控
5、栈区:非静态的局部变量:函数的参数、返回值
6、命令行参数及环境变量表:存储命令行参数、环境变量
注意:堆内存的使用从低地址想高地址,栈的使用为从高地址向低地址,并且在
堆和栈之间有一段空隙
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 常属性全局变量
const int const_global = 100;
// 初始化的全局变量
int init_global = 100;
// 末初始化的全局变量
int uninit_global;
int main(int argc,char* argv[],char* environ[])
{
// 常属性静态局部变量
const static int const_static = 100;
// 初始化的静态局部变量
static int init_static = 100;
// 末初始化的静态局部变量
static int uninit_static;
// 常局部变量
const int const_local;
// 局部变量
int local;
// 堆地址
void* heap_ptr = malloc(4);
// 字符串字面值地址
const char* const_str = "hehe";
printf("----------从低到高依次是----------\n");
printf("代码段:%p\n",main);
printf("只读段:%p %p %p\n",&const_global,&const_static,const_str);
printf("数据段:%p %p\n",&init_global,&init_static);
printf("BSS段:%p %p\n",&uninit_global,&init_static);
printf("堆:%p\n",heap_ptr);
printf("栈:%p %p\n",&const_local,&local);
printf("命令行参数:%p\n",argv[0]);
printf("环境变量表:%p\n",environ[0]);
printf("cat /proc/%d/maps\n",getpid());
getchar();
}
环境变量表
环境变量表
main函数的第三个参数char **environ
extern来获取环境变量environ
环境变量函数
int clearenv(void) 清空环境变量表
成功返回0,失败返回-1
char* getenv(const char* name) 获取环境变量的值
name:环境变量名称
成功返回地址,失败返回NULL
int putenv(char* string) 添加环境变量,sring存在则更新,不存在则添加
string:要添加的环境变量
成功返回0,失败返回-1
int setenv(const char* name,const char* value,int overwrite);
设置name环境变量的值为value
name:环境变量的名字
value:要修改的值
overwrite:不为0则更新,为0则不变
int unsetenv(const char* name) 从环境变量表中删除name
注意:操作系统中的环境变量是一块特殊的存储空间,程序自己添加的环境变
量需要自己准备存储空间,并且该环境变量只能影响自己,不能影响别人