linux动态内存分配

2018-05-20 12:29:01

进程可以通过增加堆的大小来分配内存,堆就是一段长度可变的连续的虚拟内存,开始于未初始化数据段末尾,随着内存的分配和释放增减。通常堆的当前内存边界称为program break。最初,program break正好位于未出华数据段末尾之后(&end位置)。

当program break位置上升后,程序可以访问新分配的任何内存地址,而此时物理内存尚未分配,内核会在进程试图首次访问这些虚拟内存地址时才分配物理内存页。

下面来讲讲2个操作program break的系统调用:brk()和sbrk(),虽然在代码中我们很少用到,但是了解下有助于我们弄清内存分配的工作过程。

int brk(void *end_data_segment);
void *sbrk(intptr_t increment);

系统调用brk()会将program break设置为参数end_data_segment所指定的位置,由于虚拟内存是以页为单位分配的,end_data_segment实际会四舍五入到下一个内存页的边界处。

sbrk()将program break在原来的地址上增加increment大小,并返回前一个program break的位置。所以sbrk(0)则返回当前program break位置。

获取内存页大小

//pagesize=4096
printf("pagesize=%d\n", getpagesize());


malloc()和free()

相较于brk()和sbrk(),他们更简单,允许分配小块内存,允许随意释放内存。malloc分配的内存会自动对齐。比如我的64位linux会以16字节对齐。

free()用来释放所指的内存块,通常情况下,free()并不降低program break的位置,而只是将这块内存添加到空闲内存列表,供后续的malloc()函数循环使用。这样做的好处是

1.被释放的内存块通常位于堆的中间,而非堆的顶部,因而降低program break是不可能的。
2.这样可以最大幅度的减少sbrk的调用次数,因为系统调用更耗资源。

malloc()和free()内部实现

malloc()实现很简单,它首先会扫描之前由free()所释放的空闲内存块,以一定策略(first-fit或best-fit)找到大于或等于要求的一块空闲内存,如果有直接返回,如果是大块内存,则对其进行分割返回,其他的继续保留在空闲内存列表。malloc分配内存时会额外分配几个字节用来存储内存大小如图,而实际返回给用户的是这个长度记录字节之后。

如果找不到,则会调用sbrk()以分配更多的内存。为了减少sbrk()的调用次数,sbrk()会申请更多的内存。

内存操作应该遵循以下几个规则:

1.分配一块内存后应该谨慎使用,避免操作该内存以外的字节。
2.不允许释放一个内存超过1次。
3.如果不是由malloc函数包分配的内存,决不能用free()函数释放。

分配对齐的内存memalign()和posix_memalign()

我们知道malloc已经帮我们实现了内存对齐,比如我的64位linux为16字节对齐,所以大多数情况下都不需要下面2个函数来手动指定对齐参数。只有在一些特殊场合malloc满足不了的时候才会用下面2个函数。

void *memalign(size_t boundary, size_t size);
分配size个字节内存,内存的起始地址时参数boundary的整数倍,而boundary必须是2的整数次幂。返回分配内存的地址。

int posix_memalign(void **memptr, size_t alignment, size_t size);
已分配的内存地址通过memptr返回,内存的起始地址必须是alignment的整数倍,alignment必须是sizeof(void*)与2的整数次幂两者的乘积。


在栈上分配内存:alloca()

void *alloca(size_t size);
在栈上分配的内存不能手动释放,栈帧的移除(函数返回)的时候自动释放,速度比在堆上分配更快。另一个优点是在信号处理程序中调用longjmp()或siglongjmp以执行非局部跳转时,起跳函数和落地函数之间的函数中如果使用了malloc()来分配内存,想要避免内存泄漏及其困难,甚至不可能。但是alloca完全可以避免这个问题,因为堆栈是由这些调用展开的,当堆栈重置,栈帧被移除时,内存会随栈帧一起被移除。


总结

本文对linux内存分配以及相关的做了简单的介绍,如果有疑问可以给我留言。


备注

1.编译器版本gcc4.8,运行环境centos7 64位
2.原文地址http://www.freecls.com/a/2712/2c

©著作权归作者所有
收藏
推荐阅读
  • err
    linux进程

    进程是一个可执行程序的实例。程序包含了一系列信息,这些信息描述了如何在运行时创建一个进程,所包含的内容如下。1.二进制格式标识,linux上用的是elf格式2.机器语言指...

  • err
    linux文件io(open、read、write、close)

    所有执行io操作的系统调用都是以文件描述符(大于0的整数)来指代打开的文件。文件描述符可以表示诸如管道(pipe)、fifo、socket、终端、设备和普通文件。对于每个...

  • err
    linux系统调用及错误处理

    系统调用是内核提供给外部程序的接口,进程可以通过系统调用来一自己的名义来执行某些动作。在深入了解系统调用之前,先关注以下几点。1.系统调用处理器会从用户态切换到核心态以便...

  • linux内核简介

    内核是用来管理和分配计算机资源的,它主要有进程调度、内存管理、提供文件系统、创建和终止进程、对设备的访问、联网、提供系统调用的接口等。内核还可以为内阁用户模拟出抽象的虚拟私有计算机,每个用户都可以登录...

  • linux centos7 安装逻辑卷指令来支持lvm2

    报如下错时。-bash: pvcreate: command not found-bash: pvscan: command not found-bash: pvdisplay: command no...

  • nginx模块 ngx_http_headers_module

    ngx_http_headers_module 模块是用来增加 Expires 和 Cache-control,或者是任意的响应头。Syntax: add_header name value [alw...

  • nginx模块 ngx_http_gunzip_module、ngx_http_gzip_module、ngx_http_gzip_static_module

    ngx_http_gunzip_module 模块将文件解压缩后并在响应头加上 "Content-Encoding: gzip" 返回给客户端。为了解决客户端不支持gzip压缩。编译的时候带上 --w...

  • nginx模块 ngx_http_flv_module、ngx_http_mp4_module

    ngx_http_flv_module模块提供了对 flv 视频的伪流支持。编译的时候带上 --with-http_flv_module。它会根据指定的 start 参数来指定跳过多少字节,并在返回数...

  • nginx模块 ngx_http_fastcgi_module

    ngx_http_fastcgi_module 模块使得nginx可以与 fastcgi 服务器通信。比如目前要使得 nginx 支持 php 就得使用 fastcgi技术,在服务器上装上 nginx...

  • nginx模块 ngx_http_autoindex_module

    ngx_http_autoindex_module 模块可以将uri以 / 结尾时,列出里面的文件和目录。Syntax: autoindex on | off; Default: autoindex ...

简介
天降大任于斯人也,必先苦其心志。