1. brk:是系统调用接口:

内核的syscall_table.s 中定义:
    ENTRY_SAME(brk)

例如:

在malloc函数实现中有调用brk

malloc 函数调用链中:

malloc-->expand_heap-->__expand_heap

即在__expand_heap调用系统brk函数:

__syscall(SYS_brk, 0);

注意:malloc中,当if (n > MMAP_THRESHOLD) 一般是128K,使用mmap分配内存了,否则使用brk分配内存。

C语言的标准库里,分配内存使用的函数是malloc,calloc,realloc,它们并不是Linux系统分配内存的API。
Linux系统分配用户内存的API是brk()。它的作用就是改变数据段的末尾位置,也就是改变进程的brk的位置。

进程的brk之前的内存,就是可以使用的堆内存。移动brk的位置,就可以分配内存。
brk()函数,是Linux的一个系统调用。它的调用号是45。 <4.4.4内核版本>


sbrk()函数,是C库在brk()基础上实现的一个库函数。

2. sbrk:是glibc封装的一个应用函数,sbrk其实是调用系统接口brk:

glibc的sbrk.c文件中:

void *sbrk(intptr_t inc)

{

if (inc) return (void *)__syscall_ret(-ENOMEM);

return (void *)__syscall(SYS_brk, 0);

}

3. sys_brk

Linux内核的brk()系统调用,原型是这样的:
void* sys_brk(void* addr);


把当前进程的数据段末尾brk设置成地址addr。
如果设置成功了,就会返回与addr一样的brk值。
如果设置失败了,就返回进程当前的brk值。
所以在C库里要记录上一次的brk值,来判断是否设置成功,以给用户返回0或者-1。

注:

C库中 又把brk()系统调用包装了一下,包装成c库的sbrk()和brk()函数:

其中sbrk()用于分配内存,brk()用于释放内存。
实际上Linux只有一个brk()系统调用,sbrk()并不是系统调用,而是基于brk系统调用的扩展实现。

4. 附上__expand_heap和__simple_malloc简短代码实现:

/* Expand the heap in-place if brk can be used, or otherwise via mmap,

* using an exponential lower bound on growth by mmap to make

* fragmentation asymptotically irrelevant. The size argument is both

* an input and an output, since the caller needs to know the size

* allocated, which will be larger than requested due to page alignment

* and mmap minimum size rules. The caller is responsible for locking

* to prevent concurrent calls. */

static void *__expand_heap(size_t *pn)

{

static uintptr_t brk;

static unsigned mmap_step;

size_t n = *pn;

if (n > SIZE_MAX/2 - PAGE_SIZE) {

errno = ENOMEM;

return 0;

}

n += -n & PAGE_SIZE-1;

if (!brk) {

brk = __syscall(SYS_brk, 0);

brk += -brk & PAGE_SIZE-1;

}

if (n < SIZE_MAX-brk && !traverses_stack_p(brk, brk+n)

&& __syscall(SYS_brk, brk+n)==brk+n) {

*pn = n;

brk += n;

return (void *)(brk-n);

}

size_t min = (size_t)PAGE_SIZE << mmap_step/2;

if (n < min) n = min;

void *area = __mmap(0, n, PROT_READ|PROT_WRITE,

MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

if (area == MAP_FAILED) return 0;

*pn = n;

mmap_step++;

return area;

}

-----------------------------------------------------------------------------

static void *__simple_malloc(size_t n)

{

static uintptr_t brk, cur, end;

static unsigned mmap_step;

size_t align=1;

void *p;

if (n > SIZE_MAX/2) {

errno = ENOMEM;

return 0;

}

if (!n) n++;

while (align<n && align<ALIGN)

align += align;

LOCK(lock);

cur += -cur & align-1;

if (n > end-cur) {

size_t req = n - (end-cur) + PAGE_SIZE-1 & -PAGE_SIZE;

if (!cur) {

brk = __syscall(SYS_brk, 0);

brk += -brk & PAGE_SIZE-1;

cur = end = brk;

}

if (brk == end && req < SIZE_MAX-brk

&& !traverses_stack_p(brk, brk+req)

&& __syscall(SYS_brk, brk+req)==brk+req) {

brk = end += req;

} else {

int new_area = 0;

req = n + PAGE_SIZE-1 & -PAGE_SIZE;

/* Only make a new area rather than individual mmap

* if wasted space would be over 1/8 of the map. */

if (req-n > req/8) {

/* Geometric area size growth up to 64 pages,

* bounding waste by 1/8 of the area. */

size_t min = PAGE_SIZE<<(mmap_step/2);

if (min-n > end-cur) {

if (req < min) {

req = min;

if (mmap_step < 12)

mmap_step++;

}

new_area = 1;

}

}

void *mem = __mmap(0, req, PROT_READ|PROT_WRITE,

MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

if (mem == MAP_FAILED || !new_area) {

UNLOCK(lock);

return mem==MAP_FAILED ? 0 : mem;

}

cur = (uintptr_t)mem;

end = cur + req;

}

}

p = (void *)cur;

cur += n;

UNLOCK(lock);

return p;

}

sbrk brk sys_brk 函数区分相关推荐

  1. sbrk/brk函数用法

    头文件unistd.h sbrk/brk函数重新指定数据段的结束位置,sbrk(0)获得当前数据段结束地址 sbrk(增量),增量可正,可负,可为0,都返回原来数据段的结束地址.失败返回-1 brk( ...

  2. linux brk函数,Linux sbrk/brk函数使用整理

    sbrk/brk: brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的: 每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只 ...

  3. (转)C#中的Abstract和Virtual函数区分,因我老弄不明白这个问题,所以转到这儿

    发现很多朋友对于C#中的Abstract和Virtual函数区分得不是很清楚,下面我通过两段代码让大家看看这两者之间到底有什么区别~~ 开发环境: VS.net 2005 使用方法: 用以下代码覆盖p ...

  4. 用API函数区分U盘和移动硬盘

    用API函数GetDriveType可以区分盘符是U盘的盘符还是移动硬盘的盘符,具体如下 GetDriveType("X://") == DRIVE_REMOVABLE 即U盘的盘 ...

  5. opencv converTO()函数 转换图像的数据类型不改变通道数,注意与cvtColor()改变颜色空间/彩色空间/色彩空间函数区分

    注意与cvtColor()函数的区别,cvtColor改变颜色空间,通道数也会改变,converTo只改变数据类型,不改变通道数,原来是几个通道转换后还是几个通道 示例: src.convertTo( ...

  6. brk函数 linux,brk和sbrk及内存分配函数相关-linux+内存

    brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的: 每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空 ...

  7. 操作系统知识整理——Linux下进程的内存布局以及brk()、sbrk()函数探究

    文章目录 前言 一.内存堆栈模型 二.系统栈和用户栈 三.函数调用时的内存栈分配 四.brk(), sbrk() 用法详解 前言 本篇文章是自己在学习xv6操作系统内核时,发现自己对进程在内存中的布局 ...

  8. Linux中brk()系统调用,sbrk(),mmap(),malloc(),calloc()的异同【转】

    转自:http://blog.csdn.net/kobbee9/article/details/7397010 brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的: ...

  9. brk(), sbrk() 用法详解【转】

    转自:http://blog.csdn.net/sgbfblog/article/details/7772153 贴上原文地址,好不容易找到了:brk(), sbrk() -- 改变数据段长度 brk ...

最新文章

  1. 用XP做服务器突破10人限制
  2. jeesite如何已生成数据的数据源_jeesite1.X 集成多数据源
  3. Flash存储控制器组成!(flash)
  4. MySQL和PostgreSQL的常用语法差异
  5. 数据结构 - 树形选择排序 (tree selection sort) 具体解释 及 代码(C++)
  6. discuz精仿OPPO社区主题模板
  7. python 数据呈现_新手小白初学Python数据可视化 清晰呈现数据变化
  8. python中求2-1000的完数_C++求2→1000之间的完数。
  9. 工程测量(道路、桥梁、隧道、地下管线、高速铁路)
  10. 慈溪视频软件测试,慈溪论坛
  11. 2021年危险化学品生产单位安全生产管理人员报名考试及危险化学品生产单位安全生产管理人员模拟考试
  12. 激发波长近红外二区发光量子点,近红外二区(NIR-II)发射波长(1000-1700 nm)
  13. matlab图像转为灰度,matlab怎么读取一幅图像,并转换为灰度图像
  14. ubuntu免费画图工具
  15. Linux C网络编程基础
  16. 时间序列分析之AR模型、MA模型和ARMA模型(二)
  17. 日语在线学习网站简介
  18. vue引入百度地图实现轨迹绘制
  19. 必应每日壁纸批量下载
  20. [转]读研or工作--阿里巴巴吴翰清的邮件[技术性内容, 慎入]

热门文章

  1. FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of me
  2. 就在今天!当当科技品类日满100减50
  3. 人为何有指纹【转自生物谷】
  4. Juju and Binary String(前缀和)
  5. 多渠道归因分析(Attribution):传统归因(一)
  6. 杰理之音量控制【篇】
  7. 机房监控系统的组成及功能!
  8. 倒计时牌(react )
  9. mac上启动nginx遇到80端口被占用的解决方法(猜了好久的坑我擦)
  10. 基于asp.net网上选课系统设计