Linux环境编程2

内存管理(了解框架和规则)

    用户层

        STL   自动分配/释放内存 调用C++

        C++   new/delete      调用C

        C     malloc/free     调用POSIX

        POSIX brk/sbrk        调用Linux系统函数

        Linux mmap/munmap     调用内核(kernel)

    系统层

        内核  kmalloc/vmalloc  调用驱动

        驱动  get_free_pape

    

    进程映像

        程序是存储在磁盘上的可执行文件,当程序运行时,系统会将可执行文件记载到内存中,形成了进程(一个程序是可以同时加载多个进程的)

        进程的内存空间分布情况就是进程映像,从低地址到高地址依次分布为:

            text    代码段      二进制指令、常量(字符串字面值、被const修饰过的原data段) 

                                只读,如果修改就会段错误

            data    数据段      初始化过的全局变量和静态局部变量

            bss     静态数据段  未初始化过的全局变量和静态局部变量

                                该段内存会被自动清理为0

            heap    堆          体量较大的数据,例如结构变量

                                手动管理、释放时间可控、空间大、使用麻烦、与指针配合使用 可能产生内存泄漏、内存碎片

            stack   栈          局部变量、块变量

                                操作系统自动管理、使用方便、不会产生内存泄漏、内存碎片

                                大小有限、释放不受控制

            environ 环境变量表  环境变量每个进程都有一份,修改不会影响其他进程

            argv    命令行参数  程序运行开始时附加的参数 例如cp

    虚拟内存

        1、系统会为每个进程分配4G虚拟内存空间

            4G: 32个0~32个1

                0xFFFFFFFF

        2、用户只能使用虚拟内存地址,无法直接使用真实的物理地址

        3、虚拟地址与物理内存进行映射后才能使用,否则就会产生段错误

        4、虚拟地址与物理内存的映射是由操作系统来动态维护的

        5、让用户使用虚拟地址一方面为了内存安全,另一方面操作系统可以让每个进程使用比实际物理内存更大的地址空间

        6、4G的虚拟地址分为两个部分

            [0,3G) 用户空间

            [3,4G) 内核空间

            注意: 所有进程的内核映射都是同一块,统一管理所有的用户映射

        7、用户空间的代码不能直接访问内核空间的代码和数据,可以通过系统调用(API)的方式切换到内核态,间接地与内核交换数据

        8、如果对虚拟地址越界访问(使用了没有映射成功的虚拟内存)将导致段错误

    映射虚拟内存与物理内存的函数:

        #include <unistd.h>

        注意: 系统映射内存时是以页(1页 = 4096字节)为单位的

        系统映射内存时会维护一个指针,指向内存映射的最后一个字节的下一个位置

        

        int brk(void* addr); (brk.c)

        功能: 直接使用addr的值修改位置指针的位置

        addr:

            > 原来位置指针 映射内存

            < 原来位置指针 取消映射

        返回值: 成功返回0,失败返回-1

        void* sbrk(intptr_t increment); (sbrk.c)

        功能: 通过增量参数的方式调整该指针的位置,从而达到映射或者取消映射的目的

        increment: 增量

            0 获取原来的位置

            >0 映射内存

            <0 取消映射

            返回值: 原来的位置

        注意: sbrk/brk都具有映射、取消映射的功能,但是配合使用(sbrk映射、brk取消映射)是最方便的

        #include <sys/mman.h>

        void* mmap(void* addr,size_t length,int port,int flags,int fd,off_t offset);

        功能: 映射虚拟地址与物理内存,brk和sbrk底层调用的就是它们

        addr: 映射内存区域的首地址,可以自己指定,如果是NULL,则系统会自动指定

        length: 映射的字节数长度

        prot: 映射的权限

            PROT_EXEC   执行权限

            PROT_READ   读权限

            PROT_WRITE  写权限

            PROT_NONE   没有权限

        flags:

            MAP_SHARED 对映射区域的写操作直接反映到文件中

            MAP_PRIVATE 对映射区域的写操作只放映到缓冲区中

            注意: 前两个必选其一,后两个根据情况自己选择

            MAP_ANONYMOUS 映射虚拟内存到物理内存中,而不是映射文件,想当于忽略fd、offset

            MAP_FIXED 如果提供的addr无法映射,则直接失败,系统不会自动调整

        fd: 文件描述符

            注意: 如果不想要映射文件与物理内存,则写0

        offset:

            文件内容的偏移量,如果不映射文件,也给0

        返回值: 成功返回映射后的内存地址,失败返回0xFFFFFFFF或者(void*)-1

        int munmap(void* addr,size_t length);

        功能: 取消映射

        addr: 取消映射区域的起始地址

        length: 内存的字节数

        返回值: 成功返回0,失败返回-1

        注意: 命令 strace ./a.out 可以跟踪程序的执行过程,从而发现函数底层调用了谁

    内存管理总结:

        1、mmap/munmap 底层是不维护任何东西,只返回一个映射后的内存首地址,所映射的内存位于堆中

        2、brk/sbrk 底层维护一个指针,记录了所映射的内存结尾下一位,所映射的内存也是位于堆中,底层调用了mmap/munmap

        3、malloc/free 底层维护了一个双向链表和必要的维护信息,所映射的内存也是位于堆中,底层调用了brk/sbrk

        4、每个进程都有4G的虚拟内存空间,虚拟内存只是个数字,必须与物理内存建立映射关系才能使用

        5、平时所说内存的分配和释放有两层含义:

            a、权限的分配和释放

            b、映射关系的建立和取消

        6、重点不是sbrk/brk/mmap/munmap函数的用法,而是理解Linux系统的内存管理机制

练习1: 打印出各个段的数据的地址,与该进程的内存记录文件进行对比(test1.c)

    scanf("%*c");

    获取进程号:

        1、ps -aux 查看a.out的进程号 去 /proc/pid/maps 对比

        2、#include <sys/types.h>

           #include <unistd.h>

           getpid() 获取当前进程的进程号

练习2: 计算前1000个素数,存储到堆内存中,但尽量不要浪费内存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值