可能是重复问题:
在C语言中,free和malloc是如何工作的?
考虑这样一种情况:我需要通过malloc分配20个字节大小的内存。为了使malloc()函数调用成功,这20个字节必须在内存中连续吗?还是可以分散在多个位置?例如,在上述情况下,如果有4或5个10字节的块,malloc会起作用吗?或者这取决于操作系统或编译器?
可能是重复问题:
在C语言中,free和malloc是如何工作的?
考虑这样一种情况:我需要通过malloc分配20个字节大小的内存。为了使malloc()函数调用成功,这20个字节必须在内存中连续吗?还是可以分散在多个位置?例如,在上述情况下,如果有4或5个10字节的块,malloc会起作用吗?或者这取决于操作系统或编译器?
malloc
函数将会成功返回一个大小等于请求的内存块,该内存块在程序的堆内存空间中是逻辑连续的,否则将返回空指针。"逻辑连续"意味着使用这种类型的 malloc
:int *ip; /* Nothing yet allocated (other than the size of a pointer... */
int ar[100]; /* 100 ints on the STACK */
ip = (int *)malloc(sizeof ar); /* if that succeeds, 100 ints on the HEAP */
该函数将在您的操作系统的堆上为100个整数分配空间,并返回NULL或指针。另外,数组ar
是在栈上分配的。每个数组都将被逻辑地放置在所有整数旁边,至少在程序知道的范围内如此。如果它们不相邻,则无法使用array[offset]
符号或指针算术来将这些块作为数组寻址。
然后,您可以通过数组访问或指针访问交替访问堆栈或堆块的内存,就像这样:
ip[2]=22; /* the second element of ip[] is '22' */
*(ar+33)=3333; /* the 33 element of ar is '3333' */
i=*(ip+2); /* assign using pointers */
j=ar[33]; /* assign using array offsets */
malloc
返回的内存块与您的程序不是逻辑上连续的,您将无法使用指针算术或数组下标访问该块。malloc
分配的块不能移动,如果它影响程序用于访问该块的指针,则您将具有高度碎片化的内存。(它可以被透明地移动,但不要指望那是有效的。)realloc
根据需要增加和缩小内存。realloc的一个大问题是指向现有数据的指针可能会更改,因此只使用1个指针。realloc允许操作系统根据HEAP上可用的内容更好地移动数据。这样,您将(大多数情况下)避免了内存碎片化的可能性。malloc
是C标准中定义的用于分配连续内存块的函数(至少对用户来说是这样),如果分配失败则返回空指针。
更底层地讲,操作系统会执行像kotlinski或Blank Xavier在各自的回答中所描述的操作。
以下内容摘自ISO/IEC 9899-1999 C标准的§7.20.3:
如果通过calloc、
realloc
或malloc
分配成功,则返回的指针已经适当地对齐,以便将其指定为任何类型对象的指针,然后使用该空间分配的对象或对象数组的访问(直到显式释放该空间为止)。
虽然该段落没有明确说明,但它提到了“访问对象数组”,而在C标准中,数组是:
数组类型描述了一组具有特定成员对象类型(称为元素类型)的连续分配非空对象。(来自于§6.2.5)
此外,连续调用calloc
、realloc
和malloc
不保证内存的相对位置或顺序(与已分配的其他内存块相比)。
这一点也在§7.20.3中说明:
通过连续调用
calloc
、malloc
和realloc
函数所分配的存储空间的顺序和连续性未指定。
realloc
的后续调用将会返回指向该大小的连续内存块的指针,或者失败。如果在正确分配之前进行了分配,则它还将保护该区域中的现有数据。指针可能会改变,数据的绝对地址也可能会改变,但是如果 realloc
成功,您将拥有原始数据和调整大小的块作为一个块。关于 realloc
,您最后的陈述是错误的... - dawg这是平台特定的。在软件层面上,对于你的眼睛来说,它总是呈现为你malloc了20个连续的字节。但在某些平台上,例如具有分页内存的平台,当涉及到实际硬件时,这些字节实际上并不需要是连续的-它只是看起来是这样的。
针对不同的操作系统。
如果这是一个具有虚拟内存的系统,malloc将会分配另一页虚拟内存并将其添加到堆中,然后将所需的内存交给您。但是,页面内的内存块必须是连续的。有趣的是,如果您的需求大于页面大小,则物理内存中的内存块不必是连续的。两个虚拟内存页面可以被连接起来,而无论它们在物理内存中的位置如何。
如果这是一个没有虚拟内存的系统,那么是的,您请求的所有内存都需要在物理内存中是连续的。
7.20.3内存管理函数
calloc、malloc和realloc函数分别调用时分配的存储空间的顺序和连续性是未指定的。如果分配成功,则返回的指针适当对齐,以便可以将其分配给任何类型的对象指针,然后用于访问所分配的空间中的此类对象或此类对象的数组(直到明确释放该空间)。分配的对象的生存期从分配到释放。每个这样的分配都应产生指向与任何其他对象不相交的对象的指针。返回的指针指向分配空间的开始(最低字节地址)。如果无法分配空间,则返回空指针。如果请求的空间大小为零,则行为是实现定义的:要么返回空指针,要么行为就像大小为一些非零值,但返回的指针不得用于访问对象。
7.20.3.3 malloc函数
malloc函数为大小由size
指定且值不确定的对象分配空间。
很可能它不会起作用。malloc无法重新排列已分配的内存,因此无法创建一个连续的20字节空闲块。它只能向操作系统请求另一页内存,然后从中切割出20个字节+头。
realloc
内存,在各种情况下它可以给你完全相同的位置。这是因为通常 malloc 实现会给你比你请求的内存更多的内存(例如,一种流行的方案是将内存分成桶,每个桶包含一定大小的内存区域;然后 malloc 将从一个可以容纳所需大小的桶中给你一个元素)。此外,malloc 不会为微小的大小请求新页面,只有在桶为空时才会这样做。不过,当分配大块内存时,它通常会请求。 - DarkDust
malloc
返回的指针。 - dawg