malloc如何运作?

可能重复:
free和malloc如何在C中工作?

考虑一种情况,我必须通过malloc分配大约20个字节的内存。 对于malloc()的函数调用是否成功,20个字节是否应该在内存中连续可用或者是否可以分散? 例如,在上面的例子中,如果有4个或5个块,每个10个字节,malloc会工作吗? 或者这是特定于操作系统还是特定于编译器?

这个问题有点不对劲。

在典型的OS中,存在虚拟存储器和物理存储器的概念。

物理内存通常存在于4kb块中,虚拟内存同样存在。

每个进程都有虚拟内存 – 对于每个进程,操作系统都会显示完全可寻址的内存范围。 因此,在32位机器上,每个进程“认为”它具有4 GB的内存。

实际上,操作系统在幕后忙于将虚拟内存分配映射到实际的物理内存块上。 因此,例如,400kb虚拟内存分配被映射到100个物理块。 那些物理块不需要是有条件的(并且几乎从来都不是 – 没有什么能阻止它发生,但是在进行任何工作的机器上,这是非常不可能的)但是虚拟内存分配确实需要是有意义的。

所以你仍然可以遇到虚拟内存碎片。 这里,进程请求存储器块,并且在该特定进程虚拟存储器映射中,不存在可以满足请求的虚拟存储器块。

那个问题是你想到的问题。

malloc的调用将成功从程序的HEAP内存空间返回一个逻辑连续的内存 ,该内存空间等于请求的大小,或者它将使用NULL指针失败。 “逻辑连续”意味着使用此类型的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 */ 

将在HEAP上为您的操作系统分配100个整数的空间,并返回NULL或指针。 另外,arraysar在STACK上分配。 每个数组都将按照逻辑上彼此相邻的方式布局,至少在程序知道的范围内。 如果它们不是彼此相邻,则无法将这些块作为具有array[offset]表示法的array[offset]或使用指针算法来处理。

然后,您可以使用数组访问或指针访问交换访问STACK或HEAP内存块,如下所示:

 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返回的内存块在逻辑上与您的程序不连续,则无法使用指针算法或数组下标访问该块。

在幕后,您的操作系统可能会移动其他可移动的内存块,使用虚拟内存,将其他项目交换到虚拟内存等,以增加分配给您的程序的HEAP。 Malloc可以是一个非常快速或非常昂贵的调用 – 取决于该系统上发生的其他事件以及分配给您的程序的HEAP空间。

HEAP内存(使用C中的动态系统调用访问的部分)可能会出现碎片。 假设您分配了内存稀缺的20字节块的数量。 现在,您可以释放这些块的每个其他块的图像。 您将拥有高度碎片化的内存,因为如果它影响程序用来访问块的指针,则无法移动使用malloc分配的块。 (它可以透明地移动,但不要指望它是有效的。)

如果要对HEAP内存进行多次调用,请考虑更改逻辑以使用realloc根据需要增大和缩小内存。 使用realloc的一个很大的问题是指向现有数据的指针可能会发生变化,因此只能使用指针指向它。 Realloc允许操作系统根据需要移动数据,以更好地适应HEAP上可用的数据。 您(大多数时候)会以这种方式避免内存碎片化的可能性。

对于20字节的快速块,请考虑使用STACK。 这就是它的用途。 看看这篇SOpost ,看看STACK与HEAP的特征。

阅读calloc,malloc,realloc的C指南,免费获取更多信息。

标准malloc在C标准中定义为分配一个连续的内存块(至少对你来说是这样) – 如果分配失败,它将返回一个空指针。

在较低级别,操作系统将执行类似kotlinski或Blank Xavier在各自答案中所描述的内容。

ISO / IEC 9899-1999 C标准的 §7.20.3开始

如果分配(通过callocreallocmalloc )成功,则返回指针,以便可以将其分配给指向任何类型对象的指针,然后用于访问此类对象或此类对象的数组已分配 (直到空间被明确释放)。

它不是那么明确,但段落提到’访问这样的对象的数组’,而在C标准中,数组是:

数组类型描述了具有特定成员对象类型的连续分配的非空对象集,称为元素类型。 (来自§6.2.5

另请注意,后续调用callocreallocmalloc不保证内存的连续性或排序(已分配其他内存块)。

这一点也在§7.20.3中规定。

通过连续调用callocmallocrealloc函数分配的存储的顺序和连续性未指定。

这是特定于平台的。 对于您的眼睛,在软件级别,它将始终显示为malloc:ed 20连续字节。 但是在某些平台上,例如使用分页内存,这些字节在涉及到实际硬件时并不需要连续 – 它只会出现。

内存必须是连续的 – 你提到的内容通常被称为内存碎片 ,并且是应用程序获取和释放内存的真正问题。

OS特定。

如果它是一个具有虚拟内存的系统,malloc就会分配另一个VM页面并将其添加到其堆中,然后将所需的内存交给您。 然而,页面中的内存块必须是连续的。 有趣的是,如果您的需求大于页面大小,则内存不必在物理内存中连续。 无论物理存储器位于何处,都可以使两页VM连续。

如果它是一个没有VM的系统,那么是的,您请求的所有内存都需要在物理内存中连续。

ISO C99标准:

7.20.3内存管理function
通过连续调用calloc,malloc和realloc函数分配的存储的顺序和连续性未指定。 如果分配成功,则返回指针,以便可以将其指定给指向任何类型对象的指针,然后用于在分配的空间中访问此类对象或此类对象的数组(直到空间被明确释放) 。 分配对象的生命周期从分配延伸到解除分配。 每个这样的分配都应该产生一个指向与任何其他对象不相交的对象的指针。 返回的指针指向分配空间的开始(最低字节地址)。 如果无法分配空间,则返回空指针。 如果请求的空间大小为零,则行为是实现定义的:返回空指针,或者行为就像大小是非零值一样,但返回的指针不应用于访问对象。

7.20.3.3 malloc函数
malloc函数为一个对象分配空间,该对象的大小由size指定,其值是不确定的。

换句话说,如果要求20字节对象的空间,就可以获得足够的空间来容纳20字节的对象。

最有可能它不起作用。 malloc无法重新排列已分配的内存,因此无法生成20字节的连续空闲块。 它只能要求操作系统从中获取另一页内存,其中可以切断20个字节+标题。