分享

brk sbrk函数

 Double360 2014-04-18
在UNIX/LINUX中,程序运行时动态内存以堆的方式来分配。程序而言,它使用的动态内存地址是虚拟内存,

代码用内存和数据用内存,一个从上往下,一个从下往上增长。
在LINUX,X86中,可用虚拟内存为0x00000000--0xffffffff;
对每一个进程都是一个独立的4GB空间。
但前面的1GB是内核用的,后面某一个位置才是程序运行时动态内存堆
的开始地址,你用多少它向上增多少。

比如语句  malloc(1024);

首先虚拟内存向上增长1024;//LINUX,kernel中do_brk();
然后系统使用mmap(),为这虚拟内存映射物理内存。
虚拟内存对物理内存的切入切出是另外的
理论上十分高深的东东,能写数米厚书而实际上就几行代码的东东,
你有时间看看linux内核代码中的mmap()。

说明几点,
程式分配虚拟内存也不是你要一个字节就给你一个字节,
而是你要一个字节给你一个页面,因为映射物理内存时只能以页为单位。
你要另一个字节时,它在这个页面的剩余空间给你。

注意大部份UNIX虚拟内存的使用是只增不减的。

malloc(32 * 1024) --->;sbrk += 32 * 1024
free()                  --->;sbrk 不减少。
但如如果再来一次
malloc(32 * 1024) ---->;sbrk 也不增,使用原有空间.

但对于LINUX来说它是要以内存的最大数收缩的;

a = malloc(32 * 1024) -->;sbrk += 32 * 1024
b = malloc(32 * 1024) -->;sbrk += 32 * 1024
if(****){
    free(b);   --->;sbrk -= 32 * 1024;
}
else{
    free(a);   --->;sbrk 不减少。只是多了个空洞.
}



/* linux kernel code */
brk()
/*
*  sys_brk() for the most part doesn't need the global kernel
*  lock, except when an application is doing something nasty
*  like trying to un-brk an area that has already been mapped
*  to a regular file.  in this case, the unmapping will need
*  to invoke file system routines that need the global lock.
*/
asmlinkage unsigned long sys_brk(unsigned long brk)
{
        unsigned long rlim, retval;
        unsigned long newbrk, oldbrk;
        struct mm_struct *mm = current->;mm;
        down_write(&mm->;mmap_sem);
        if (brk < mm->;end_code)
                goto out;
        newbrk = PAGE_ALIGN(brk);
        oldbrk = PAGE_ALIGN(mm->;brk);
        if (oldbrk == newbrk)
                goto set_brk;
     /******虚拟内存在这里收缩******/
        /* Always allow shrinking brk. */
        if (brk <= mm->;brk) {
                if (!do_munmap(mm, newbrk, oldbrk-newbrk))
                        goto set_brk;
                goto out;
        }
        /* Check against rlimit.. */
        rlim = current->;rlim[RLIMIT_DATA].rlim_cur;
        if (rlim < RLIM_INFINITY && brk - mm->;start_data >; rlim)
                goto out;
        /* Check against existing mmap mappings. */
        if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
                goto out;
        /* Check if we have enough memory.. */
        if (!vm_enough_memory((newbrk-oldbrk) >;>; PAGE_SHIFT))
                goto out;
        /* Ok, looks good - let it rip. */
        if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
                goto out;
set_brk:
        mm->;brk = brk;
out:
        retval = mm->;brk;        /****这就是返回值*****/
        up_write(&mm->;mmap_sem);
        return retval;
}

在LINUX中sbrk(0)能返回比较精确的虚拟内存使用情况,
在SOLARIS/HP中sbrk(0)返回以页为单位的虚拟内存使用情况。


这样我们就可以用sbrk来得到程式当前使用内存情况。




我时常使用sbrk(0)来返回我的程式当前使用了多少内存。
main(){
    int start,end;
    start = sbrk(0);
    ....
    malloc(***);
    ....
    end = sbrk(0);
    printf("hello I used %d vmemory",end - start);
}

打字打得累死好像还是没有说明白sbrk,没时间打了。


综上所述,我把楼的的那句话
Calling sbrk with an increment of 0 can be used to find the current location of the program break
理解为使用sbrk(0)可以返回当前的程序所有使用的虚拟内存 达到/越过 了的地址。

sbrk把程序的数据段增加increment个字节。sbrk不是一个系统调用,而是一个C的库函数。用increment为0来调用sbrk函数,可以返回程序当前所停留的数据段位置。
jianyan的程序两个sbrk返回值相减得出占用内存情况,应该就是前后两个调用时,数据段当前指针相减,所以得出内存占用的大小。

更多 0

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多