从操做系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(固然在这里是不考虑共享内存)web
brk是将数据段(.data)的最高地址指针_edata往高地址推;
mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存。
注:svg
在开辟空间的时候只是在进程的虚拟地址空间内开辟指定大小的内存,可是并无实际在物理内存上面开辟空间,只有当对开辟的内存空间进行访问的时候才会在物理内存上面开辟实际的空间。例如:假如开辟的空间一直没有使用,那么在物理内存上面始终没有实际的空间。操作系统
在这之间当对开辟的内存进行第一次访问的时候会发生缺页中断,这时候系统就会在指定的空间进行开辟内存,而后再将物理内存的地址映射到虚拟地址上面。指针
当发生缺页中断的时候系统会干什么?
一、检查要访问的虚拟地址是否合法
二、查找/分配一个物理页
三、填充物理页内容(读取磁盘,或者直接置0,或者啥也不干)
四、创建映射关系(虚拟地址到物理地址) code
状况1:xml
当使用malloc小于128k的内存,使用brk分配内存,将_edata往高地址推(只分配虚拟空间,不对应物理内存(所以没有初始化),第一次读/写数据时,引发内核缺页中断,内核才分配对应的物理内存,而后虚拟地址空间创建映射关系)
blog
在开辟较小的空间的时候会直接将_edata寄存器的指向向髙地址必定指定大小的位置,而后将这个区域映射到虚拟内存地址空间内。可是这时候这个位置并无实际的物理内存,只有当使用到这块内存的时候才会在物理内存上面开辟空间。进程
状况2:
当开辟的空间大小大于128K的时候并非使用brk系统来移动_edata指向来开辟空间,而是使用mmap系统在堆栈之间的共享区直接开辟指定大小的空间(虚拟空间)。
图片
一样,在开辟空间以后并无实际的物理内存空间,当使用的时候才会初始化。内存
free
当须要销毁的时候,使用mmap开辟的空间会直接释放,若是在物理内存上面开辟的有实际的内存的话也会一块儿释放。当时使用brk开辟的内存只能依次释放,好比:释放b的时候能够直接释放虚拟内存和物理内存,可是在释放a的时候若是在a的上面还有开辟的空间,那么a这块空间并不会被释放,由于在a的上面还有开辟的空间,可是a这块空间是能够复用的,那么若是在下次开辟空间的时候又开辟了和啊大小的空间,那么颇有可能系统就会直接将a这块空间映射到虚拟空间内。
由于使用brk开辟的内存必须等髙地址的内存释放以后才会释放,这也是内存碎片产生的缘由。
释放a:
释放b:
当c也释放的时候,那么_edata指向就会从新回退到含有开辟空间的位置上面。