回顾:
静态库(.a)和共享库(.so)
ar -r gcc -shared -fpic
gcc xx.c -l库名称 -L库路径
动态调用共享库
dlopen dlsym dlclose dlerror
C的错误处理
1 函数中关于错误的设计
用 返回值 代表是否产生错误
返回int类型 用 -1 代表错误
返回指针类型 用 NULL代表错误
不用考虑错误返回值 void
2 对错误的处理
提供了一个全局变量errno 存放错误的编号
strerror - 用编号取得对应的错误信息
perror printf - 打印错误信息
环境变量和环境表
环境表就是所有环境变量的合集,是一个首地址。
类型是 字符指针数组。
环境变量的相关函数:
getenv putenv setenv unsetenv clearenv
Unix/Linux内存管理
Unix/linux的内存相关函数和调用关系
STL -> 内存自动分配和自动回收
|
C++ -> new/delete运算符 new分配 delete回收
|
C语言 -> malloc()分配 free()回收
|
Unix系统函数 -> sbrk() brk() 分配和回收
|
Unix系统函数 -> mmap()分配 munmap()回收
| Unix/Linux的用户层内存关系
------------------------------------------
| 内核层(了解)
kmalloc() vmalloc()
|
get_free_page()
内存分配时,函数图 由上到下 调用。
进程和程序
程序:在硬盘上的 可以执行的文件
进程:在内存中 运行起来的 程序
一个进程的内存空间包括以下几个部分:
1 代码区: 程序的代码(函数)放入代码区,只读区
2 全局区:存放全局变量和static变量,main函数执行之前 分配全局区
3 BSS段: 存放未初始化的全局变量,main函数执行之前 清空BSS段(清0)。
4 栈区:非static的局部变量,包括函数的参数。栈区的内存 自动分配和自动回收。
5 堆区:也叫自由区,malloc()、free()就是操作堆区内存,程序员完全掌控堆区内存的分配和回收。
6 只读常量区:常量和字符串字面值(" "),只读区,有些资料 没有分出只读常量区,而是统称为代码区。
关于内存的地址(虚拟内存地址)
每个进程都先天设定了0-4G的虚拟内存地址(不是内存的真实地址,只是一个编号),虚拟内存地址开始时不对应任何的内存,直接使用会引发段错误。程序员所接触的都是虚拟内存地址。虚拟内存地址必须映射物理内存(或者硬盘上的文件)以后才能 存储数据。
虚拟内存地址中,0-3G 是用户空间,是 用户层使用,3G-4G 是内核空间,是 内核层使用。用户层不能直接访问内核层,可以 通过 Unix的系统函数访问内核层。UC课程主要研究 Unix系统函数。
内存管理的最小单位 是一个内存页,每页大小是4096字节(4K),虚拟内存地址连续时,物理内存地址可以不连续。两个内存页的物理地址 可能不挨着。即使只申请一个字节的内存,也会映射 至少一个内存页。
多次申请内存时,第一次映射物理内存,后面不会再映射物理内存,除非内存使用完毕。
关于字符串赋值方式:
= 改变地址,stcpy改变值。
如果不能改变地址的字符串(char[])赋值用strcpy
如果不能改变值的字符串(指向只读区)赋值用=
const 修饰的变量 值真的不能改么?
可以改,只要用 指针 指向就可以。
const int i = 10;
//i = 9;//错
int* pi = &i;
*pi = 9;//可以改 但不推荐使用
Linux系统 把几乎一切都做成了文件,内存的情况也存成了文件。 /proc/进程ID/maps 文件存储了内存的分页情况。
cat /proc/进程ID/maps 就可以查看。
ps -aux 可以查看进程ID
maps 其实不是硬盘上的,是内存中的数据。
关于malloc和free :
malloc()一次映射33个内存页,malloc分配内存时,除了数据区域外,还额外需要保存一些信息。底层有一个双向链表保存额外信息。
如果malloc累计的空间超过了33个内存页,会重新映射新的物理内存。free()并不保证一定会释放内存,如果到了最后33个内存页,等到进程结束才释放。
如果一次申请的字节数超过33页,实际分配的内存页数会稍大于申请的页数,但和33就没关系。 getpagesize()函数可以获取当前内存页的大小。
getpagesize()函数可以获取当前内存页的大小。