您的位置:首页 > 其它

brk, sbrk 函数

2012-02-05 18:54 387 查看


NAME

brk, sbrk - change data segment size

SYNOPSIS

#include <unistd.h>;

int brk(void *end_data_segment);

void *sbrk(ptrdiff_t increment);

DESCRIPTION

brk sets the end of the data segment to the value specified by

end_data_segment, when that value is reasonable, the system does have

enough memory and the process does not exceed its max data size (see

setrlimit(2)).

sbrk increments the program's data space by increment bytes. sbrk

isn't a system call, it is just a C library wrapper. Calling sbrk with

an increment of 0 can be used to find the current location of the pro-

gram break.

RETURN VALUE

On success, brk returns zero, and sbrk returns a pointer to the start

of the new area. On error, -1 is returned, and errno is set to ENOMEM.
在UNIX/LINUX中,程序运行时动态内存以堆的方式来分配。

对程序而言,它使用的动态内存地址是虚拟内存,

代码用内存和数据用内存,一个从上往下,一个从下往上增长。

在LINUX,X86中,可用虚拟内存为0x00000000--0xffffffff;

对每一个进程都是一个独立的4GB空间。

但前面的1GB是内核用的,后面某一个位置才是程序运行时动态内存堆

的开始地址,你用多少它向上增多少。

比如语句 malloc(1024);

首先虚拟内存向上增长1024;//LINUX,kernel中do_brk();

然后系统使用mmap(),为这虚拟内存映射物理内存。

虚拟内存对物理内存的切入切出是另外的

理论上十分高深的东东,能写数米厚书而实际上就几行代码的东东,

你有时间看看linux内核代码中的mmap()。

说明几点,

程式分配虚拟内存也不是你要一个字节就给你一个字节,

而是你要一个字节给你一个页面,因为映射物理内存时只能以页为单位。

你要另一个字节时,它在这个页面的剩余空间给你。

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

CODE:
[Copy to clipboard]

malloc(32 * 1024) --->;sbrk += 32 * 1024

free() --->;sbrk 不减少。

但如如果再来一次

malloc(32 * 1024) ---->;sbrk 也不增,使用原有空间.
但对于LINUX来说它是要以内存的最大数收缩的;

CODE:
[Copy to clipboard]

a = malloc(32 * 1024) -->;sbrk += 32 * 1024

b = malloc(32 * 1024) -->;sbrk += 32 * 1024

if(****){

free(b); --->;sbrk -= 32 * 1024;

}

else{

free(a); --->;sbrk 不减少。只是多了个空洞.

}

CODE:
[Copy to clipboard]

/* 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返回值相减得出占用内存情况,应该就是前后两个调用时,数据段当前指针相减,所以得出内存占用的大小。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: