Linux系统的内存管理
1 局部优先法则 只要局部变量定义,就会屏蔽全局变量。
内存管理
1.1 内存区域的划分
代码区 只读常量区 全局区/数据区 BSS段 堆区 栈区
8048444 80486c0 804a 804a 808f bfa1e
总结
1 按照地址从小到大的排列 进程中的内存区域依次是:代码区 只读常量区 全局区/数据区 BSS段 堆区 栈区。
2 其中代码区和只读常量区统称为代码区,全局区数据区和BSS段,统称为全局区或者数据区。在
3 在进程的内存区域的最上面,用来存放命令行参数和环境变量。堆区和栈区没有明显的分割线。可以进行微调,并且堆区的分配一般按照地址从小到大进行,而栈区的分配一般按照从大到小进行分配。
1.2 字符串的存储形式之间的比较
指针变量的指向可以改变,但是数组名的指向不可以改变。
指针变量指向的字符串内容不可以改变,数组存储的内容可以改变。因为 :不可以修改只读常量区的内容。
对于存放常量字符串的堆区来说,指针的指向和指针指向的内容都可以改变。
1.3 虚拟内存管理技术
unix/linux 系统的内存都是采用虚拟内存管理技术进行管理,每个进程都有0-4G的内存地址,(虚拟的不是真的存在的),由操作系统负责吧虚拟内存地址和真是的物理地址映射取来,因此,不同的进程中虚拟地址空间看起来是相同的,但是对应的物理内存是不同的。
其中0-3G的虚拟空间叫做用户空间,其中3-4G空间之间的虚拟地址空间叫做内核空间,用户程序一般运行在用户空间,内核空间只有系统内核才能访问,用户程序不能直接访问内核空间,但是系统内核提供一些系统函数负责将程序从用户空间切换到内核空间执行,执行完毕后再切换回到用户空间。
内存地址的基本单位是字节,内存映射的基本单位是内存页,目前主流的操作系统的内存页大小是4KB(4096字节)。
1.4 段错误的由来
1 scanf 函数的使用,没加取地址符号
2 指针的使用之中 int *pi;野指针 int *pi =NULL; 空指针。
再用scanf 也会引发段错误。
3 使用未映射的虚拟地址
4 对没有操作权限的内存进行操作
例如 对只读常量区进行写操作,可能引发段错误。
1.5 使用malloc 函数申请动态内存
1 使用malloc 申请动态内存的注意事项。
使用malloc 函数申请内存时候,除了申请的多需要的内存大小之外,可能还会申请额外的12 个字节,用来存储一些管理内存相关的信息,比如内存的大小等等。
2 使用malloc 申请内存,不能对所申请的内存空间进行越界访问,避免造成数据结构的破坏
3#include
getpid(); 获取当前进程的进程号。
cat 查看内容 /proc/进程号/maps 用来查看指定内存的分配情况
使用malloc 申请原则
一般来说,使用这个函数申请比较小的动态内存时候,操作系统会一次性分配33个内存页的大小,最终的目的就是为了提高效率,
利用 size a.out查看a.out 的内存分配。
1.6 使用free 函数释放动态内存
十六进制的1000就是一个内存页,一般来说使用malloc 来分配比较大的内存时候,系统会分配34个内存页,当所申请的内存超过34时候,系统会再次分配33个内存页,也就是按照33 个内存页为基本单位
而使用free 来释放内存时候,则释放多少就减少多少,当使用free 释放完毕所有的内存时候,系统可能保留33个内存页来方便再次申请使用,提高效率。
1.7 内存管理的相关函数
1 getpagesize 函数
函数功能
主要用来获取当前内存页的大小,一般来说是4kb;
2 sbrk 函数
功能:#include
void *sbrk (intptr_t increment);
函数功能 主要是用来调整动态内存的大小,可增加和减少。参数可以是整数和负数。
increment 如果大于0;表示申请内存空间,参数increment<0;表示释放内存,如果=0;表示获取当前内存空间的当前位置。
返回值 如果成功返回调整内存大小之前的位置,失败返回 (void* )-1;
一般使用sbrk 申请比较小的内存,系统默认分配一个内存页大小,一旦申请的内存页超过一个内存页的时候,再次分配一个内存页,也就是按照一个内存页为基本单位进行分配,而释放内存时候,如果释放之后剩下的内存足够用一个内存页表示,则一次性释放一个内存页。
使用sbrk 申请内存不会申请额外的内存空间来管理相关信息
使用sbrk 函数申请内存比释放内存方便
3 brk 函数
功能 : int brk(void *addr);
函数功能: 主要用于根据参数指定的目标位置调整内存的大小,
目标位置和之前目标位置相比,来确定是分配还是回收内存。
需要先获取当前位置来作为基准位置,
使用brk 函数释放内存比较方便,因此一般都使用sbrk 和brk 函数配合使用。
使用sbrk 函数申请内存,使用brk 函数释放内存,首先申请一个int 类型的大小空间,存放100;再申请一个double 类型空间放3.14。最后申请一个长度是10 个字节的字符空间,存放hellow ,要求打印上述三个变量,释放内存。