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

附件列表

    原文地址:https://www.cnblogs.com/LyndonMario/p/9362271.html