最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

brk和sbrk工作原理

IT圈 admin 64浏览 0评论

2024年5月31日发(作者:清妙梦)

brk和sbrk及内存分配函数相关

brk

sbrk

主要的工作是实现虚拟内存到内存的映射

.

GNUC

,

内存分配是这样的

:

每个进程可访问的虚拟内存空间为

3G

,但在程序编译时,不可能也没必要为程序分

配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从这一块分配的。

如果这块空间不够,

malloc

函数族(

realloc

calloc

等)就调用

sbrk

函数将数据段的下界移

sbrk

函数在内核的管理下将虚拟地址空间映射到内存,动,供

malloc

函数使用。(参见

linux

内核情景分析)

7 v. m7 J7 T- T- {1 v+ b. p2 i

#

include

4 F: m# t2 Z B p0 i2 q

int brk(

void

*end_data_segment);

2 S3 J |: I% i6 g) P

void *sbrk(ptrdiff_t increment);

# ?1 m0 b) G" `( l, l0 d* J; u6 A: d

DESCRIPTION

2 U1 }1 l, q7 r' J+ ~2 r/ L3 v/ S; `

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)).

4 y K) v/ b%

_

' m1 Y5 N d J4 `

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 program break.

RETURN VALUE

On success, brk

return

s zero, and sbrk returns a pointer to the

start

of the new

area. On

error

, -1 is returned, and errno is set to ENOMEM.

j3 f7 N2 g7 R2 W- `1 Y

, ?: |0 p" t( |$ x! }4 w" `

sbrk

不是系统调用,是

C

库函数。系统调用通常提供一种最小功能,而库函数通常提供比

较复杂的功能。

- X8 F- H' z2 _: C R

Linux

系统上,程序被载入内存时,内核为用户进程地址空间建立了代码段、数据段和堆

栈段,在数据段与堆栈段之间的空闲区域用于动态内存分配。

% a3 W# j- T+ F" [! H$ h5 u

内核数据结构

mm_struct

中的成员变量

start_code

end_code

是进程代码段的起始和终止地

start_data

end_data

是进程数据段的起始和终止地址,

start_stack

是进程堆栈段起始地址,

址,

start_brk

是进程动态内存分配起始地址(堆的起始地址),还有一个

brk

(堆的当前最

后地址),就是动态内存分配当前的终止地址。

! K: |6 s* a f: V, V, h

C

语言的动态内存分配基本函数是

malloc()

,在

Linux

上的基本实现是通过内核的

brk

系统

调用。

brk()

是一个非常简单的系统调用,只是简单地改变

mm_struct

结构的成员变量

brk

值。

mmap

系统调用实现了更有用的动态内存分配功能,可以将一个磁盘文件的全部或部分内容

映射到用户空间中,进程读写文件的操作变成了读写内存的操作。在

linux/mm/mmap.c

文件

do_mmap_pgoff()

函数,是

mmap

系统调用实现的核心。

do_mmap_pgoff()

的代码,只是新

建了一个

vm_area_struct

结构,并把

file

结构的参数赋值给其成员变量

m_file

,并没有把文

件内容实际装入内存。

x S9 n( R. D* a* _! u

Linux

内存管理的基本思想之一,是只有在真正访问一个地址的时候才建立这个地址的物理

映射。

======================================================================

============

C

语言跟内存分配方式

1

从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个

运行期间都存在。例如全局变量,

static

变量。

2

在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执

行结束时这些存储单元自动被释放。栈内存分配运

6 p% F3 ~ D8 0 L5 K5 S

算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

3

)从堆上分配,亦称动态内存分配。程序在运行的时候用

malloc

new

申请任意多少的

内存,程序员自己负责在何时用

free

delete

释放内存。动态内存的生存期由我们决定,使

用非常灵活,但问题也最多

( h7 |% n$ l$ v! @

C

语言跟内存申请相关的函数主要有

alloc,calloc,malloc,free,realloc,sbrk

.

其中

alloc

是向栈

申请内存

,

因此无需释放

. malloc

分配的内存是位于堆中的

,

并且没有初始化内存的内容

,

因此

基本上

malloc

之后

,

调用函数

memset

来初始化这部分的内存空间

.calloc

则将初始化这部分的

内存

,

设置为

0.

realloc

则对

malloc

申请的内存进行大小的调整

.

申请的内存最终需要通过

函数

free

来释放

.

sbrk

则是增加数据段的大小

;

( v- W$ p, p v# v4 |

malloc/calloc/free

基本上都是

C

函数库实现的

,

OS

无关

.C

函数库内部通过一定的结构来保

存当前有多少可用内存

.

如果程序

malloc

的大小超出了库里所留存的空间

,

那么将首先调用

brk

系统调用来增加可用空间

,

然后再分配空间

.free

,

释放的内存并不立即返回给

os,

而是保

留在内部结构中

.

可以打个比方

: brk

类似于批发

,

一次性的向

OS

申请大的内存

,

malloc

函数则类似于零售

,

满足程序运行时的要求

.

这套机制类似于缓冲

.

使用这套机制的原因

:

系统调用不能支持任意大小的内存分配

(

有的系统调用只支持固定大

小以及其倍数的内存申请

,

这样的话

,

对于小内存的分配会造成浪费

;

系统调用申请内存代价

昂贵

,

涉及到用户态和核心态的转换

.

函数

malloc()

calloc()

都可以用来分配动态内存空间,但两者稍有区别。

3 o1 Q3 i' k; N2 ?

malloc()

函数有一个参数,即要分配的内存空间的大小:

void *malloc(size_t size);

calloc()

函数有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就

是要分配的内存空间的大小:

; [+ S% n y0 q% F9 _. G0 ^! P

void *calloc(size_t numElements

size_t sizeOfElement)

" ]$ R4 k! N- s* p! w! S

2024年5月31日发(作者:清妙梦)

brk和sbrk及内存分配函数相关

brk

sbrk

主要的工作是实现虚拟内存到内存的映射

.

GNUC

,

内存分配是这样的

:

每个进程可访问的虚拟内存空间为

3G

,但在程序编译时,不可能也没必要为程序分

配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从这一块分配的。

如果这块空间不够,

malloc

函数族(

realloc

calloc

等)就调用

sbrk

函数将数据段的下界移

sbrk

函数在内核的管理下将虚拟地址空间映射到内存,动,供

malloc

函数使用。(参见

linux

内核情景分析)

7 v. m7 J7 T- T- {1 v+ b. p2 i

#

include

4 F: m# t2 Z B p0 i2 q

int brk(

void

*end_data_segment);

2 S3 J |: I% i6 g) P

void *sbrk(ptrdiff_t increment);

# ?1 m0 b) G" `( l, l0 d* J; u6 A: d

DESCRIPTION

2 U1 }1 l, q7 r' J+ ~2 r/ L3 v/ S; `

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)).

4 y K) v/ b%

_

' m1 Y5 N d J4 `

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 program break.

RETURN VALUE

On success, brk

return

s zero, and sbrk returns a pointer to the

start

of the new

area. On

error

, -1 is returned, and errno is set to ENOMEM.

j3 f7 N2 g7 R2 W- `1 Y

, ?: |0 p" t( |$ x! }4 w" `

sbrk

不是系统调用,是

C

库函数。系统调用通常提供一种最小功能,而库函数通常提供比

较复杂的功能。

- X8 F- H' z2 _: C R

Linux

系统上,程序被载入内存时,内核为用户进程地址空间建立了代码段、数据段和堆

栈段,在数据段与堆栈段之间的空闲区域用于动态内存分配。

% a3 W# j- T+ F" [! H$ h5 u

内核数据结构

mm_struct

中的成员变量

start_code

end_code

是进程代码段的起始和终止地

start_data

end_data

是进程数据段的起始和终止地址,

start_stack

是进程堆栈段起始地址,

址,

start_brk

是进程动态内存分配起始地址(堆的起始地址),还有一个

brk

(堆的当前最

后地址),就是动态内存分配当前的终止地址。

! K: |6 s* a f: V, V, h

C

语言的动态内存分配基本函数是

malloc()

,在

Linux

上的基本实现是通过内核的

brk

系统

调用。

brk()

是一个非常简单的系统调用,只是简单地改变

mm_struct

结构的成员变量

brk

值。

mmap

系统调用实现了更有用的动态内存分配功能,可以将一个磁盘文件的全部或部分内容

映射到用户空间中,进程读写文件的操作变成了读写内存的操作。在

linux/mm/mmap.c

文件

do_mmap_pgoff()

函数,是

mmap

系统调用实现的核心。

do_mmap_pgoff()

的代码,只是新

建了一个

vm_area_struct

结构,并把

file

结构的参数赋值给其成员变量

m_file

,并没有把文

件内容实际装入内存。

x S9 n( R. D* a* _! u

Linux

内存管理的基本思想之一,是只有在真正访问一个地址的时候才建立这个地址的物理

映射。

======================================================================

============

C

语言跟内存分配方式

1

从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个

运行期间都存在。例如全局变量,

static

变量。

2

在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执

行结束时这些存储单元自动被释放。栈内存分配运

6 p% F3 ~ D8 0 L5 K5 S

算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

3

)从堆上分配,亦称动态内存分配。程序在运行的时候用

malloc

new

申请任意多少的

内存,程序员自己负责在何时用

free

delete

释放内存。动态内存的生存期由我们决定,使

用非常灵活,但问题也最多

( h7 |% n$ l$ v! @

C

语言跟内存申请相关的函数主要有

alloc,calloc,malloc,free,realloc,sbrk

.

其中

alloc

是向栈

申请内存

,

因此无需释放

. malloc

分配的内存是位于堆中的

,

并且没有初始化内存的内容

,

因此

基本上

malloc

之后

,

调用函数

memset

来初始化这部分的内存空间

.calloc

则将初始化这部分的

内存

,

设置为

0.

realloc

则对

malloc

申请的内存进行大小的调整

.

申请的内存最终需要通过

函数

free

来释放

.

sbrk

则是增加数据段的大小

;

( v- W$ p, p v# v4 |

malloc/calloc/free

基本上都是

C

函数库实现的

,

OS

无关

.C

函数库内部通过一定的结构来保

存当前有多少可用内存

.

如果程序

malloc

的大小超出了库里所留存的空间

,

那么将首先调用

brk

系统调用来增加可用空间

,

然后再分配空间

.free

,

释放的内存并不立即返回给

os,

而是保

留在内部结构中

.

可以打个比方

: brk

类似于批发

,

一次性的向

OS

申请大的内存

,

malloc

函数则类似于零售

,

满足程序运行时的要求

.

这套机制类似于缓冲

.

使用这套机制的原因

:

系统调用不能支持任意大小的内存分配

(

有的系统调用只支持固定大

小以及其倍数的内存申请

,

这样的话

,

对于小内存的分配会造成浪费

;

系统调用申请内存代价

昂贵

,

涉及到用户态和核心态的转换

.

函数

malloc()

calloc()

都可以用来分配动态内存空间,但两者稍有区别。

3 o1 Q3 i' k; N2 ?

malloc()

函数有一个参数,即要分配的内存空间的大小:

void *malloc(size_t size);

calloc()

函数有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就

是要分配的内存空间的大小:

; [+ S% n y0 q% F9 _. G0 ^! P

void *calloc(size_t numElements

size_t sizeOfElement)

" ]$ R4 k! N- s* p! w! S

与本文相关的文章

发布评论

评论列表 (0)

  1. 暂无评论