回顾:
环境表 - getenv() putenv() setenv() ...
内存管理 - 函数调用的关系图(Unix/Linux)
STL - 自动
C++ - new delete
C - malloc() free()
Unix- sbrk() brk()
Unix- mmap() munmap()
一个进程的内存空间:
代码区 只读常量区 全局区 BSS段 堆 栈
虚拟内存地址
通常程序员所接触的都是虚拟内存地址,虚拟内存地址每个进程都先天存在,是0-4G的数字,其中0-3G叫用户空间,3G-4G 内核空间。用户空间可以 通过 系统函数(系统调用) 进入内核空间。
虚拟内存地址先天存在 但不能直接存储数据,必须映射物理内存/硬盘文件 才能真正存储数据,否则 引发段错误。
段错误的发生条件:
1 虚拟内存地址没有映射 物理内存/硬盘文件
2 执行了没有 操作权限的行为。
malloc() 和 free()
malloc()一次分配33个内存页,超出后再次分配一组内存页,如果一次性申请的内存超过33个内存页,会分配多一点的内存页。
free()只是把内存 由 已经使用 换到 未使用,不一定会解除映射。
今天:
sbrk() brk()
mmap() munmap()
系统调用的概念
sbrk() brk()底层都维护了一个位置,
sbrk(increment)
当 increment 为正时,位置向后移动increment字节,同时返回移动之前的位置,相当于分配内存。
当 increment 为负时,位置向前移动increment字节,相当于释放内存,其返回值没有实际意义。
当 increment 为零时,不移动位置,只返回当前位置。
sbrk()便于 申请内存,但 释放内存很不方便,
brk()则相反。
brk()参数是 新的位置。
mmap() / munmap()
很多的权限、选项、设置都可以用 位或 连接。
读 1 0 0
写 0 1 0
读写 1 1 0 (位或)
练习:
使用mmap()/munmap()函数实现分配内存,存储某个员工的信息。员工是一个结构,成员包括id,name,salary。
系统调用
用户空间的代码不能直接访问内核空间,因此 内核空间提供了 一系列的函数实现 用户空间进入内核空间的接口(桥梁),这一系列的函数 统称为 系统调用(System Call)。
程序由 用户层进入内核层时,会把用户层的状态先封存起来,然后到内核层运行代码,运行结束以后,从内核层出来到用户层时,再把数据加载回来。因此,频繁的系统调用效率较低。
time 命令可以测试 程序在用户层 和 内核层的运行时间。
文件和目录
在Linux中,几乎一切都被看成了文件。
因此文件操作函数:(系统调用)
open()/close()/read()/write()/ioctl()
可以操作几乎所有输入输出设备。
open() 打开一个文件
int open(char* filename,int flag,...)
filename 表示文件名(带路径)
flag 是打开的标识,可以选择打开方式,常见值
O_RDONLY O_WRONLY O_RDWR - 选择打开的权限
O_CREAT - 如果不存在会新建,存在则打开
O_TRUNC -和O_CREAT结合使用,打开时清空文件
O_EXCL -和O_CREAT结合使用,但文件存在时不打开,而是返回 -1 代表错误
O_APPEND - 追加的方式打开文件
... 代表0-n个任意类型的参数,如果是新建文件需要第三个参数,如果只是打开文件不需要第三个参数,新建文件时,第三个参数是 新建文件的权限(必须)。
返回 文件描述符,-1 代表出错。
文件描述符本身就是一个非负整数,代表一个打开的文件。文件open的过程:
先打开一个文件 -> 用文件表记录该文件信息 ->
在文件描述符总表中,找没使用的文件描述符(默认找最小) -> 把最小的文件描述符和文件表对应起来,放入文件描述符总表中。
文件描述符0 1 2被系统占用,分别代表标准输入、标准输出和标准错误,打开文件的描述符从3 开始。
read() 和 write()
读数据和写数据
三个参数:
第一个参数 fd
第二个参数 void*
第三个参数 read() 用sizeof(),write()用实际想写入的字节数
作业:(用Uc函数)
1 实现文件的复制
2 把员工信息写入文件,并在另外一个文件中读出来
肬c函数)
1 实现文件的复制
2 把员工信息写入文件,并在另外一个文件中读出来