linux-03-内存管理

昨天的复习:环境标 就是内存中环境变量的首地址,是一个 字符指针数组,以NULL元素作为结束,环境表的引入方式:extern char ** environ;

main()函数的第三个参数也是环境表的首地址

今天:关于环境变量的标C库函数Unix/LInux的内存管理(机制和实现函数)环境变量库函数:(只针对本进程)getenv()/setenv()/putenv()unsetenv()/clearenv()

getenv() -按环境变量的名 取得 环境变量的值

setenv() 新增环境变量或修改/不改变 已经存在的环境变量

putenv()  新增环境变量或是修改已存在环境变量

unsetenv() 删除一个环境变量

clearenv() 删除全部的环境变量

Unix/Linux的内存管理(UC的真正的开始)

内存分配和回收的相关函数及实现关系进程的内存空间划分

虚拟内存地址空间机制内存管理的相关函数:

自动管理内存  STL容器(各种数据结构)/JAVA

  |

  new分配      C++的内存管理delete回收 

|

malloc()分配free()回收  C程序员的内存管理 

|

sbrk() brk()    Unix系统函数 UC程序员 (既能分配也能回收) 

|

mmap()分配munmap()回收  Unix系统函数 UC程序员 

|              (用户层)

------------------------------------

kmalloc() vmalloc()  (内核层)

进程的内存空间划分进程是什么?-运行在内存中的程序

程序是什么?-就是硬盘上的可执行文件,是编译连接的产物

为了沟通的方便,很多情况下,把进程也统称为程序

进程的内存空间划分为以下部分:

1.代码区 -存放代码(函数)的区域,函数指针就是指向代码区,是函数在代码区的地址。是一个只读区域。

2.全局区域 -存放全局变量和static修饰的局部变量,能读能写

3.BSS段-存放未初始化的全局变量。(没有写=的)

注:全局区和BSS段都会在main()函数执行前创建,区别在于BSS段在main()函数执行之前 会自动清0一次。

int a;int main(){int b;printf("%d,%d",a,b);//0,和随机数}

4.栈区/堆栈区(- stack)-没有用static修饰的局部变量,包括函数的形参。栈区的内存系统 系统自动管理。程序员也可以痛过特定函数进行管理的参与,但是不建议使用。

5.堆区(heap)-也叫自由区,是程序员全权管理的区域。系统不会自动对堆区做任何的事情。malloc()等函数都是在操作堆区。堆区内存的分配和回收都是由程序员完成。

6.只读常量区 - 很多书上把这个区域并入了代码区,字符串的字面值(“”括起来的)和const修饰的全局变量

虚拟内存地址空间

在Unix系统中,程序员所接触的内存地址都是虚拟内存地址,而不是真实的物理内存地址。虚拟内存地址 其实就是一个整数,本质上是不能存储数据的,需要做内存映射后才能存储数据。每个进程在启动时就先天具备了0-4G的虚拟内存地址空间(32位系统),这些地址都是一个整数,而无法存储数据。虚拟内存地址必须映射到物理内存/硬盘文件 后才能存储数据。所谓的内存分配就是 先分配未使用的虚拟内存地址,再用虚拟内存地址映射到物理内存/硬盘文件。如果使用了未映射的虚拟内存地址 存储数据就会引发 段错误。
进程之间即使是相同的虚拟内存地址 对应的物理内存也是不一样的。 Unix/Linux系统 用一个整数(虚拟内存地址) 代表一块物理内存。

虚拟内存地址是按字节管理的(一个字节有一个虚拟地址),但是在做内存映射时不是以字节为单位做映射,而是用内存页做映射的基本单位。一个内存页(32位系统)是4096(4k),函数getpagesize()可以获取内存页的大小。(空间换时间)先分配4k的空间,等用完了4k的空间再分配 malloc(4)-》分配了4字节的虚拟地址,但是映射了33页物理内存

0-4G的虚拟内存地址 分为用户空间和内核空间,用户空间是0-3G,3G-4G是内核空间,用户空间是给用户使用,内核空间是给系统内核使用,用户空间的程序不能直接访问内核空间,但可以通过Unix提供的系统函数(系统调用)进入内核空间。

关于数组和指针:大多数情况下,数组和指针可以混合使用,但是有区别:

1.sizeof()不一样,数组的sizeof()是数组的长度乘以元素的大小,而指针的sizeof()是4(32位系统)。

2.指针可以改变地址的指向,而数组是常指针(指向地址不能改变);

3.函数的返回值不能是数组,因此如果返回数组时,返回值类型必须写指针。void fa(){char *s1 = "abc";//只读常量区 因为指针的指向可以该,所以直接指向了“abc“所在的只读常量区

char s2[4] = "abc";//在堆区,因为数组是常量指针,一开始就指向了堆区,由于常量指针的指向是不可以更改的,故直接把”abc“复制到了堆区}

进程内存空间的排序次序(由小到大)

代码区 只读常量区 全局区 BSS段 堆区 栈区

堆区的分配方式是从小到大

栈区的分配方式是从大到小其中,栈区在3G左右的位置。

Linux系统 中,文件可以代表 几乎一切,内存有文件与之对应,输入输出设备 也有文件与之对应,目录 也是 文件。

cat /proc/pid/maps 可以查看内存映射的情况,其中pid就是进程编号ID,可以用getpid()函数取得(进程不结束就有效)

字符串处理和数据结构是每个程序员的基本功,作为c程序员操作字符串的基本代码。(超重要)

出 段错误的可能:1.使用了未映射的虚拟内存地址2.对内存进行了没有权限的操作,比如:修改了只读区

//字符串的基本代码

5 //c语言中,字符串只能用char *或char s[]

6 int main()

7 {

8 //1.字符串赋值 等号赋值,该的是地址,strcpy()该值,不改变指向

9    char* s1 = "abc";

10    char s2[4] = "abc";//初始化是例外,改值

11    s1 = "123";//y

12    strcpy(s1,"123");//n 段错误 只读区域是不能改值的

13    s2 = "123";//n 数组是常指针,常指针不能该地址

14    strcpy(s2,"123");//y  数组可以改元素值

15

16    char* s3 = malloc(4);

17    s3 = "123";//n 不行的原因是因为等号改变了堆区的指向,指向了只读常量区,>    虽然不会报错,但是会导致释放不了  指向只读区,堆区内存泄漏 堆区和栈区分配了>    地址,所以一般都用strcpy

18    strcpy(s3,"123");//y 直接改变值,不改变指向,所以堆区还有权限释放自己

19    printf("s4 = %s\n",s3);

20    free(s3);

21 }

你可能感兴趣的:(linux-03-内存管理)