1,内存中各个地址范围的含义
按照地址范围由低到高的顺序:0-3G的地址范围:
代码段:代码的可执行文件,一般为只读并且是共享的。(RO code/data)
数据段:存已经被初始化的全局变量(RW data) static char *user="jiangsu"
BSS段:存一些未被初始化的全局变量(ZI data) static char*user
堆:maoolc()或者new()申请的段,给程序员使用,地址向高地址范围增长(通过brk()函数扩展)
mmap区间:(一些动态库文件)
栈:函数参数等,由系统自动分配释放,地址向低地址范围增长(可以通过ulimit -s查看每个进程最大使用的栈的大小)
补充:正常代码段都不是从用户空间0地址开始的,比如arm linux嵌入式设备从0x8000(32K)开始的,前面的32k可以用来存储一些error code,如果一个函数返回一个地址,但是该地址大小小于0x8000,那么则认为此函数发生 了错误~
正常stack和kernel space之间有一段空白,BSS和heap之间也有一段空白,heap和mmp之间也有一段空白,这个称为ASLR技术,防止地址被其他人知道而遭到攻击
3-4G的空间是内核空间,用户空间的代码不能访问到。
malloc函数详解~
malloc只是一个库函数,在不同的平台对malloc有不同的实现。malloc是从堆上分配内存,但在内核中并没有堆的概念,堆只是一个应用程序的概念,在进程创建的时候,在进程的虚拟地址空间中划分出一块区域作为堆,这块区域并没有对应的物理内存,使用malloc分配内存实际上只是从这块虚拟内存区域分出更小的区域给应用程序,只有当应用程序访问这个小区域时才会产生缺页中断,从而获得物理内存。而free并不会释放物理内存,而是把在堆上分配的小区域归还给堆,这些操作都是glibc在应用层实现的。
malloc的使用过程中会使用两个系统调用brk和mmap,brk用于增长(或减小)堆的大小,在进程创建时会指定堆的起始地址(堆空间是向上增长的),而堆的大小为0,当使用malloc分配内存时发现当前堆剩余空间不够时就会调用brk增长堆的大小,实际上brk的作用就是把堆所在的虚拟内存区域的结束地址增长(或减小)到某个位置。当malloc一次分配的空间大于一个阀值大小时(比如128K),malloc不再从堆上分配空间,而是使用mmap重新映射一块虚拟地址区域,在free时调用munmap释放这一区域。这样的策略主要是方便堆管理,避免在一个很大的尺度管理堆,这样做是基于大内存分配并不常使用这个假设。
可以注意到如果分配的内存过大,在分配和释放时都要通过系统调用,效率会有降低,所以如果应用程序频繁分配大于分配阀值的内存,效率就会很低,这种应用可以通过调整分配阀值使内存分配和释放都在用户态(在堆中)完成。使用mallopt可以调整malloc的参数,M_TRIM_THRESHOLD表示如果堆大小大于该值,就应该在适当的时候收缩堆的大小,M_MMAP_THRESHOLD表示大于此值的内存分配请求要使用 mmap 系统调用。