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