• 2.环境变量,内存管理,错误处理


    一.错误处理
     通过函数返回值表示错误
     1.合法,不合法
      数组的查找
      练习:计算文件的大小
       int file_size(const char *path);
     2.NULL或其他地址(0xffffffff)
      例子:malloc,fopen,dlopen
      练习:实现memcpy
       void *mem_copy(void *dest,const void *src,size_t n);
     3.成功返回0,失败返回-1
      例子:dlclose
      练习:实现求余
       int mod(int num1,int num2,int *retp);
     4.永远成功printf
      练习:实现一个命令:./create file
     5.通过全局变量来反映错误
      errno errno.h
      strerror stdlib.h
      perror("...")
    环境变量:
     什么是环境变量:是程序了解操作系统配置的一个重要方法。
      操作系统通过环境变量来告诉程序它的资源放在什么位置
     每个程序执行后,操作系统就会给它一张环境变量表,每个程序一张。
     全局变量extern char **environ;
     也可以通过main函数参数来获取int main(int argc,char **argv,char **env)
     操作环境变量的函数:
      stdlib.h
      name=value
      //通过环境变量名获取值
      char *getenv(const char *name)
      //以name=value设置环境变量,如果环境变量存在则覆盖,不存在则添加
      int putenv(char *string);
      //以name,value方式来设置环境变量
      int setenv(const char *name, const char *value, int overwrite);
      name:环境变量名
      value:环境变量的值
      overwrite:如果环境变量已经存在,为0则不改变,非0则改变
      返回值:0成功,非0失败
      //删除环境变量
       int unsetenv(const char *name);
       //清空环境变量表
       int clearenv(void);
     练习1:实现函数显示环境变量表
      void show_env(void);
     练习2:
      1.查找显示LIBRARY_PATH的值
      2.添加环境变量CPATH
      3.设置
    内存管理:
     用户层
      STL智能管理/自动分配/分支释放
      C++ new/delete
      C malloc/calloc/realloc/free
      posix sbrk/brk
      Linux mmap/munmap
     ---------------------------------
     内核层
      kernel kmalloc/vmalloc
      Derive get_free_page
      DDR4
    进程的映像:
     1.存储在磁盘中的可执行文件叫程序
     2.把程序加载到内存中并执行,叫进程,是可执行程序的一个实例
     3.一个程序可以有很多个实例,每个进程都有一个唯一的编号
      getpid();
     4.进程在内存中的分布情况叫进程映像,从低到高依次排列情况:
      代码段:可执行文件会被加载到此处
      只读段:字面值,常量
      全局段:初始化的全局变量,静态变量
      bss段:未初始化的全局变量,静态变量
      堆:new/delete/malloc/sbrk,可能会产生内存泄漏和内存碎片
      栈:局部变量,块变量,函数返回值,大小有限(栈崩溃),数据释放可能不受控制,几乎不会产生什么管理上的错误
      命令行/环境变量:命令行执行程序时附加的参数,环境变量表。由终端,操作系统附加的数据
     
    如何查看进程映像:
     程序不结束的情况下,cat /proc/pid/maps 位置可以查看内存的分布情况
      size a.out可以查看代码段和数据段(全局段),bss段大小


    虚拟内存:
     1.每一个进程都有独立的4G(32位的OS)的虚拟地址空间
      0x00000000
      0x11111111
     2.应用程序中,用到的都是虚拟内存,永远无法访问到实际的物理内存
     3.虚拟内存不能直接使用,需要和物理内存建立映射关系才能使用,使用没有建立映射关系的虚拟内存会发生段错误。
     4.虚拟内存和物理内存的映射是由操作系统动态维护,有操作系统统一内存的管理能提高程序和系统的安全性,可以使用更多的内存,甚至比物理内存更大的内存(使用硬盘文件来模拟内存)。
     5.物理内存不能直接访问,是通过系统调用进入到内核层,然后再进行间接交换。
     6.虚拟空间的0-3G用户使用,3G-4G内核使用(所有程序有不同的0-3G,相同的1G,内核使用,所有程序都一样)
     7.在使用没有权限的内存时候发送段错误,使用没有映射过的内存会发生段错误。
     8.每个进程对应一个地址空间,两个进行地址交换是没有意义的
    进程之间如果要协同工作必须要解决通信的问题。
     9.malloc其实背后有一个双向链表在维护它的内存管理,首次向malloc申请内存时,malloc会向操作系统申请进行内存映射(首次映射33页一页(4096byte))之后的内存分配就从这33
     页中进行,当33页用完后,操作系统会再次映射33页
     当使用malloc进行内存管理时,不要破话它的维护信息,可能会影响下次内存的分配和之前内存的释放
     10.内存的映射是以页(4096byte)位单位,一页内存的字节数可以通过getpagesize()获得
     11.标准C的内存管理
        malloc:首次使用malloc申请内存时,malloc会向操作系统请求建立映射关系,操作系统会帮malloc映射33页的内存,交给malloc管理
        只要是映射过的内存,使用时就不会产生段错误,但是可能会破坏掉malloc的维护信息,造成接下来的申请释放错误,还可能产生脏数据

    清理内存:
        bzero strings.h 
        memset  string.h


        calloc 以nmemb*size的方式申请内存,而且会把内存清理为0.


        realloc 增减已有的内存,如果第一个参数为NULL,页可以用来申请内存。

        free释放内存,释放完内存记得指针置为NULL

        alloc 分配当前函数的栈内存,当函数结束时,会自动释放,只有部分操作系统支持


    Linux的内存管理函数:
     sbrk和brk维护一个内存末尾指针,
    两者都有内存的管理和释放功能
     void *sbrk(intptr_t increment);
     increment:把内存的末尾指针移动increment个字节
     返回值:上次调用sbrk/brk的内存末尾地址
     int brk(void *addr);
     addr:把内存的末尾指针设置为addr
     返回值:0成功,非0失败
     作用:释放内存很方便
     练习:使用brk/sbrk实现顺序栈的封装
    Linux内存映射函数
        它是Linux系统实现的内存管理函数,brk/sbrk就调用它们,它不光可以对虚拟地址与物理地址进行映射,还可以对虚拟地址和文件进行映射(用磁盘来模拟内存)
    这两个函数的映射以页为单位
     void *mmap(void *addr, size_t length, int prot, int flags,
                      int fd, off_t offset);
     addr:想与物理内存映射的虚拟地址,如果NULL,则让操作系统自动选择
     length:映射的字节数,如果不够一页自动补充为一页。
     prot:映射权限,读,写,执行三种
       PROT_EXEC Pages may be executed.
            PROT_READ Pages may be read.
            PROT_WRITE Pages may be written.
            PROT_NONE Pages may not be accessed.
           flags:
            MAP_SHARED映射文件
            MAP_PRIVATE 数据只写入缓存区,不更新文化
            MAP_ANON 只映射内存
        fd:
         映射文件的,文件描述符,如果不映射文件,写0
        offset:映射文件时的偏移值,如果不映射文件写0。
        返回值:映射后的内存地址
     int munmap(void *addr, size_t length);
     addr:要取消映射的内存地址
     length:字节数
     返回值:0成功,非0失败
     8bit = 8byte
     1024byte = 1kb
     1024kb = 1mb
     1024mb = 1GB
     1024GB = 1TB

    附件列表

    • 相关阅读:
      eclipse lua
      eclipse新建python项Project interpreter not specified
      Laravel Debugbar
      Java中枚举类型简单学习
      SG函数题目
      关于解决博弈论问题的SG函数
      三种典型的博弈论问题
      Java I/O 对象序列化
      Java I/O 文件加锁,压缩
      Java I/O NIO学习
    • 原文地址:https://www.cnblogs.com/LyndonMario/p/9362271.html
    Copyright © 2020-2023  润新知