一.错误处理
通过函数返回值表示错误
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