回顾
1. 错误处理
C程序员一般对错误有4种处理方式 (void、-1、指针+ -1、NULL)
C官方 提供了errno记录错误的编号,
用perror显示错误信息
strerror(errno)
printf("%m")
2. 环境表
int main(int argc, char** argv, char** env){}
extern char** environ;
environ == env
getenv/setenv/putenv/unsetenv/clearenv
3. 内存管理(偏理论)
Unix的内存管理 使用虚拟内存地址空间,程序员 接触的都是虚拟内存地址。虚拟内存地址必须 映射到物理内存才能使用。内存管理最小单位 是内存页,4096 字节(4K)。
windows xp 一簇(一内存页)
今天 : 内存管理
liujing@ubuntu:/$ cd proc
liujing@ubuntu:/proc$ ls
1 1703 194 2093 234 30 53698 99 modules
10 1708 195 21 235 31 55 acpi mounts
100 1714 196 210 236 310 55110 asound mpt
1000 1719 1968 2103 2364 311 55161 buddyinfo mtrr
101 1722 1969 2105 237 32 55192 bus net
...
...
其中数字代表活跃的正在运行的进程ID
运行a.out(其中加入while(1),不让其运行结束)
ps 只能看当前终端的
pa -aux
找到a.out进程
liujing 56455 0.0 0.0 4352 636 pts/8 S+ 09:28 0:00 ./a.out
liujing@ubuntu:/proc$ cd 56455
liujing@ubuntu:/proc/56455$ ls -al
total 0
dr-xr-xr-x 9 liujing liujing 0 Aug 11 09:28 .
dr-xr-xr-x 260 root root 0 Jul 31 17:07 ..
dr-xr-xr-x 2 liujing liujing 0 Aug 11 09:32 attr
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 autogroup
-r-------- 1 liujing liujing 0 Aug 11 09:32 auxv
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 cgroup
--w------- 1 liujing liujing 0 Aug 11 09:32 clear_refs
-r--r--r-- 1 liujing liujing 0 Aug 11 09:28 cmdline
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 comm
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 coredump_filter
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 cpuset
lrwxrwxrwx 1 liujing liujing 0 Aug 11 09:32 cwd -> /home/liujing/projects/ConsoleApplication1/bin/x64/Debug
-r-------- 1 liujing liujing 0 Aug 11 09:32 environ
lrwxrwxrwx 1 liujing liujing 0 Aug 11 09:32 exe -> /home/liujing/projects/ConsoleApplication1/bin/x64/Debug/ConsoleApplication1.out
dr-x------ 2 liujing liujing 0 Aug 11 09:28 fd
dr-x------ 2 liujing liujing 0 Aug 11 09:32 fdinfo
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 gid_map
-r-------- 1 liujing liujing 0 Aug 11 09:32 io
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 limits
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 loginuid
dr-x------ 2 liujing liujing 0 Aug 11 09:32 map_files
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 maps
-rw------- 1 liujing liujing 0 Aug 11 09:32 mem
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 mountinfo
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 mounts
-r-------- 1 liujing liujing 0 Aug 11 09:32 mountstats
dr-xr-xr-x 5 liujing liujing 0 Aug 11 09:32 net
dr-x--x--x 2 liujing liujing 0 Aug 11 09:32 ns
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 numa_maps
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 oom_adj
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 oom_score
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 oom_score_adj
-r-------- 1 liujing liujing 0 Aug 11 09:32 pagemap
-r-------- 1 liujing liujing 0 Aug 11 09:32 patch_state
-r-------- 1 liujing liujing 0 Aug 11 09:32 personality
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 projid_map
lrwxrwxrwx 1 liujing liujing 0 Aug 11 09:32 root -> /
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 sched
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 schedstat
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 sessionid
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 setgroups
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 smaps
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 smaps_rollup
-r-------- 1 liujing liujing 0 Aug 11 09:32 stack
-r--r--r-- 1 liujing liujing 0 Aug 11 09:28 stat
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 statm
-r--r--r-- 1 liujing liujing 0 Aug 11 09:28 status
-r-------- 1 liujing liujing 0 Aug 11 09:32 syscall
dr-xr-xr-x 3 liujing liujing 0 Aug 11 09:32 task
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 timers
-rw-rw-rw- 1 liujing liujing 0 Aug 11 09:32 timerslack_ns
-rw-r--r-- 1 liujing liujing 0 Aug 11 09:32 uid_map
-r--r--r-- 1 liujing liujing 0 Aug 11 09:32 wchan
// 所有的文件大小都为0
// 原因是因为它们都存储在内存里,而不是硬盘中
liujing@ubuntu:/proc/56751$ cat maps
00400000-00401000 r-xp 00000000 08:01 175585 a.out
00600000-00601000 r--p 00000000 08:01 175585 a.out
00601000-00602000 rw-p 00001000 08:01 175585 a.out
00602000-00623000 rw-p 00000000 00:00 0 [heap]
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
用 cat /proc/进程id/maps 可以查看进程的内存空间情况
进程ID 用ps -aux 查看a.out
cd /proc/进程ID
cat maps
new
- 会在分配内存(调用malloc)后 自动执行构造代码
delete
- 会在free之前 执行 析构函数的代码
malloc
- 底层需要维护 双向链表,记录一些关于内存信息。
如果该链表被破坏,在free时引发段错误。
在使用时其实非常简便,用malloc返回值(指针地址)存东西,用free释放。
malloc 一次分配33个内存页(一次性映射33页物理内存)。使用完毕后 再次映射时,不确定 分配多少。
33 * 4096 = 135168(0x21000)
cat maps时 会发现
无论malloc 一次还是多次,只要大小没有超过33个内存页, malloc会一次分配33个内存页给我们使用
每次malloc都会多出16个字节,记录malloc信息,双向链表等信息
free
- 不一定真正的释放内存(解除映射),在函数/程序结束之前,free 不会 释放最后 33个内存页的内存(不解除映射)。
从cat maps上看,如果申请的内存页多于33个,则释放时按分配的大小释放,直到其小于等于33个,之后再怎么释放,系统还是会一直保留这33个内存页,直到进程结束
如果malloc的内存超过了33个内存页,会 映射 比申请内存稍多的内存页。(实测68页)
malloc的用法
申请多少就malloc(size),用完了调用free()释放。
getpagesize() 可以取得内存页的大小。
不同的进程 即使内存地址(虚拟地址)相同,存的东西也不一样,因为映射的物理内存不同。
brk和sbrk
brk和sbrk底层由 系统维系一个 位置(position),内存的分配和回收都参考这个位置。
void sbrk(int size)
size=0 返回sbrk/brk上次的末尾地址
size>0 分配内存空间,返回上一次末尾地址
size<0 释放空间
返回 内存的首地址。
int brk(void ptr)
直接修改访问的有效范围的末尾地址
释放空间形成一个完整的page,则该页影射被解除
返回: -1:失败
sbrk一般用于内存的申请,brk一般用于内存的释放。
mmap/munmap 内存映射/解除映射
void* mmap(void* addr, size_t size, int prot,int flags,
int fd, off_t offset)
addr 可以指定首地址,一般为NULL,由操作系统指定
size 分配内存的大小,会补齐为内存页的整数倍
prot 是内存的访问权限,一般PROT_READ|PROT_WRITE
flags 是一个标识,可以设置映射 物理内存/文件,以及是否 被其它进程共享。 映射物理内存时,flags必须写上
MAP_ANONYMOUS
fd 是文件描述符,映射文件时使用
offset 是映射文件时的 指针偏移量
返回 分配内存的首地址
munmap 内存的释放
int i = 128 的 二进制
0000 0000 0000 0000 0000 0000 1000 0000
存入时:
1000 0000 -> -128
0000 0000
0000 0000
0000 0000
1000 0001 -> -127