曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5756|回复: 0
打印 上一主题 下一主题

C语言与内存分配方式

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2011-5-25 10:07:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一般来说,分配方式有以下 3 种:

1.  从静态存储区域分配
内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

2.  在栈上创建
在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

3. 从堆上分配(动态内存分配)
程序在运行的时候用 malloc 申请任意多少的内存,程序员自己负责在何时用 free 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

C语言跟内存申请相关的函数主要有 alloca, calloc, malloc, free, realloc, sbrk等。
alloca 是向栈申请内存,因此无需释放。
malloc 分配的内存是位于堆中的,并且没有初始化内存的内容,因此基本上在调用 malloc 之后会调用函数 memset 来初始化这部分的内存空间。
calloc 则将初始化这部分的内存,设置为0。
realloc 则对 malloc 申请的内存进行大小的调整。
申请的内存最终需要通过函数 free 来释放. 而 sbrk 则是增加数据段的大小。

malloc/calloc/free 基本上都是 C 函数库实现的,跟 OS 无关.C 函数库内部通过一定的结构来保存当前有多少可用内存.如果程序malloc的大小超出了库里所留存的空间,那么将首先调用 brk 系统调用来增加可用空间,然后再分配空间。free 时,释放的内存并不立即返回给OS,而是保留在内部结构中. 可以打个比方: brk 类似于批发,一次性的向 OS 申请大的内存,而 malloc 等函数则类似于零售,满足程序运行时的要求.这套机制类似于缓冲。

使用这套机制的原因:系统调用不能支持任意大小的内存分配(有的系统调用只支持固定大小以及其倍数的内存申请,这样的话,对于小内存的分配会造成浪费; 系统调用申请内存代价昂贵,涉及到用户态和核心态的转换。

函数 malloc() 和 calloc() 都可以用来分配动态内存空间,但两者稍有区别:
malloc() 函数有一个参数,即要分配的内存空间的大小:  
[C++] 纯文本查看 复制代码
void *malloc(size_t size);
        
calloc() 函数有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小:
[C++] 纯文本查看 复制代码
void *calloc(size_t numElements,size_t sizeOfElement);

如果调用成功,函数malloc()和calloc()都将返回所分配的内存空间的首地址。

malloc() 函数和 calloc() 函数的主要区别是前者不能初始化所分配的内存空间,而后者能。如果由 malloc() 函数分配的内存空间原来没有被使用过,则其中的每一位可能都是 0;反之,如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。也就是说,使用 malloc() 函数的程序开始时(内存空间还没有被重新分配)能正常运行,但经过一段时间后(内存空间已被重新分配)可能会出现问题。

calloc() 函数会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为零;如果你是为指针类型的元素分配内存,那么这些元素通常(但无法保证)会被初始化为空指针;如果你是为实数类型的元素分配内存,那么这些元素可能(只在某些计算机中)会被初始化为浮点型的零。

malloc() 函数和 calloc() 函数的另一点区别是 calloc() 函数会返回一个由某种对象组成的数组,但 malloc() 函数只返回一个对象。为了明确是为一个数组分配内存空间,有些程序员会选用 calloc() 函数。但是,除了是否初始化所分配的内存空间这一点之外,绝大多数程序员认 为以下两种函数调用方式没有区别:
[C++] 纯文本查看 复制代码
calloc(numElements ,sizeOfElement);

malloc(numElements *sizeOfElement);

需要解释的一点是,理论上(按照 ANSIC 标准)指针的算术运算只能在一个指定的数组中进行,但是在实践中,即使 C 编译程序或翻译器遵循这种规定,许多C 程序还是冲破了这种限制。因此,尽管 malloc() 函数并不能返回一个数组,它所分配的内存空间仍然能供一个数组使用(对 realloc() 函数来说同样如此,尽管它也不能返回一个数组)。

总之,当你在 calloc() 函数和 malloc() 函数之间作选择时,你只需考虑是否要初始化所分配的内存空间,而不用考虑函数是否能返回一个数组。

当程序运行过程中 malloc了,但是没有 free 的话,会造成内存泄漏。一部分的内存没有被使用,但是由于没有 free,因此系统认为这部分内存还在使用而没有进行回收,如果程序仍然不断向系统申请内存,使得系统可用内存不断减少。但是,内存泄漏仅仅指程序在运行时,程序退出时,OS 将回收所有的资源。因此。适当的重起一下程序,有时候还是有点作用。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-4-28 07:02 , Processed in 0.082639 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表