进程地址空间 - 堆管理

来源:互联网 发布:龙霸网络电视手机5.5版 编辑:程序博客网 时间:2024/05/18 00:02

堆是进程中用于动态分配变量和数据的内存区域。堆的管理对用户来说是不可见的,因为程序员只会使用标准库提供的辅助函数malloc等来分配任意长度的内存区。在kernel和malloc之间的经典接口是brk系统调用。堆是可以通过brk系统调用收缩和扩展的。新近的malloc调用使用了brk和匿名映射的组合方法,该方法提供了更好的性能。

堆是一块连续的内存区,扩展时是自下向上进行的,堆的地址范围在mm_struct中的start_brk和brk定义,start_brk定义了堆的起始地址,brk定义了堆的结束地址,start_brk是不会变化的,堆扩展或者收缩时会修改brk的值。

brk系统调用只有一个参数,用来指定brk的新的结束地址,新结束地址可以大于mm->brk(老的brk结束地址),也可以小于mm->brk。

236 asmlinkage unsigned long sys_brk(unsigned long brk) 237 { 238         unsigned long rlim, retval; 239         unsigned long newbrk, oldbrk; 240         struct mm_struct *mm = current->mm; 241  242         down_write(&mm->mmap_sem); 243  244         if (brk < mm->end_code) 245                 goto out; 246  247         /* 248          * Check against rlimit here. If this check is done later after the test 249          * of oldbrk with newbrk then it can escape the test and let the data 250          * segment grow beyond its set limit the in case where the limit is 251          * not page aligned -Ram Gupta 252          */ 253         rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; 254         if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim) 255                 goto out; 256  257         newbrk = PAGE_ALIGN(brk); 258         oldbrk = PAGE_ALIGN(mm->brk); 259         if (oldbrk == newbrk) 260                 goto set_brk; 261  262         /* Always allow shrinking brk. */ 263         if (brk <= mm->brk) { 264                 if (!do_munmap(mm, newbrk, oldbrk-newbrk)) 265                         goto set_brk; 266                 goto out; 267         } 268  269         /* Check against existing mmap mappings. */ 270         if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) 271                 goto out; 272  273         /* Ok, looks good - let it rip. */ 274         if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) 275                 goto out; 276 set_brk: 277         mm->brk = brk; 278 out: 279         retval = mm->brk; 280         up_write(&mm->mmap_sem); 281         return retval; 282 }

244 mm->end_code是代码区的结束地址,堆紧邻代码区,所以brk必然要大于mm->end_code

253~255 看起来data和heap区是紧挨着的,二者之和不能大于系统限制,RLIMIT_DATA是堆大小限制。

263~267 如果是收缩heap,那么调用do_unmap收缩堆

269~272如果是扩展heap,那么要先检查堆是否和进程中存在的内存映射区重叠,如果二者重叠,那么就无法扩展堆了

273~275 do_brk做堆的实际扩展工作。


系统调用brk实际上是基于匿名映射的实现,因此大部分用于管理内存映射的函数,都可以用于brk。



原创粉丝点击