C-您可以释放动态分配的数组的单个内存地址吗?

时间:2019-01-04 18:53:42

标签: c memory allocation

我似乎没有找到这个问题的答案。为什么您不能释放单个地址,是因为空间需要连续?如果这是答案,那么为什么在硬盘上发生碎片

5 个答案:

答案 0 :(得分:1)

  

您可以释放动态分配的数组的单个内存地址吗?

如果内存位于数组的末尾,则可以通过将realloc缩小为较小的大小来释放不需要的多余空间,但需要注意的是,实际上,您可能会获得一个指向新内存的新指针。给复制到其中的内容加上前缀,然后完全释放原始内存。

否则,不可以。 free接口被定义为仅接受从malloccallocrealloc返回的地址。

  

为什么不能释放单个地址是因为空间需要连续?

好吧,直接的答案是没有定义接口可以这样做。无法告诉free应该释放多少传入的指针。如果要释放所有内存到分配的块的末尾,请realloc执行此操作。

如果连续性对您的程序不重要,只需对每个数组元素使用单独的分配,然后分别释放它们。

  

,如果这是答案,那么为什么在硬盘上出现碎片

一种设想文件系统碎片情况的方法是,如果一个接一个地创建三个文件,然后删除中间一个文件,则两个文件之间现在会有一个空洞。

|---File 1---|--- Hole ---|---File 3---|

现在假设创建了一个新文件,因此它开始在两个文件之间的孔中,但是随着它的增长,它无法容纳在孔中,因此现在文件的其余部分位于File 3之后。在这种情况下,我们会说新文件是碎片化的。

|---File 1---|---File 4...|---File 3---|...File 4---|

这是在“硬盘驱动器”上发生的,因为文件系统是这样设计的:允许大文件跨越物理介质中的可用孔。

用于文件系统的RAM磁盘最终还将具有碎片文件。

不连续的数据结构可以被认为是“碎片化的”,例如链表或树,但这是设计使然。根据数组的定义,数组被认为是连续的。但是,文件系统上的文件不是数组。

答案 1 :(得分:1)

广泛地,您无法释放分配的内存的各个部分的原因是,它不足以证明编写支持它的软件是正确的。

C标准指定mallocfreerealloc和相关例程提供的服务。它为释放空间所做的唯一规定是使用free释放分配,并使用realloc用较小的分配代替分配。

通过提供释放分配的空间部分的服务,

C实现可以自由扩展C标准。但是,我不知道有没有这样做。如果允许程序释放任意内存,则内存管理软件将必须跟踪所有内存。这需要额外的数据和时间。此外,它可能会干扰某些用于管理内存的方案。内存管理软件可能会组织内存,以便可以从专用池中快速满足特定大小的分配,而必须收回作为专用池一部分的任意大小的部分。

如果对此类服务有需求,可以将其写成。但是多年来,程序和算法已经发展为使用现有服务,并且似乎并不需要释放分配的各个部分。通常,如果程序要使用可能会单独释放的许多对象,则它将分别分配它们。在构建各种数据结构,使用指针构造树,列表的哈希数组或其他结构等时,这很常见。数据结构通常由可以单独分配或释放的单个节点构建。因此,几乎不需要刻画要从更大的分配中释放出来的单个作品。

内存的组织与硬盘或其他存储介质上的数据的组织无关。通常,根据需要在磁盘上的任意位置和内存中的任意位置之间传输数据。在各种情况下,文件都是“内存映射”的,这意味着文件的内容在内存中可见,因此可以通过读取内存来读取文件内容,而可以通过修改内存来修改文件。但是,即使在这种情况下,文件的块在磁盘上的位置与文件的块在内存中的位置之间通常也没有任何关系。文件的块是由文件系统管理的,不一定是连续的,内存中的块是由存储系统管理的,可以在虚拟存储硬件的支持下任意重新排列。

答案 2 :(得分:0)

第一个问题,因为您只能释放一个malloc系列函数分配的全部内存

硬盘碎片与内存分配没有任何共同之处。

答案 3 :(得分:0)

内存分配被视为看似连续的内存块(尽管它可能不在物理内存中,但这无关紧要)。

没有简单的方法可以在单个内存分配中“挖一个洞”,但是您可以执行以下操作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ARRAY_LEN 11

int main (void)
{
    char *array;

    array = (char *) malloc(ARRAY_LEN);
    strcpy(array,"0123456789");

    printf("%s\n",array);

    //Remove the 5th element:
    memmove(&array[5], &array[5+1], ARRAY_LEN-5);
    array = realloc(array, ARRAY_LEN-1);
    printf("%s\n",array);

    free(array);
    return 0;
}

某些Linux文件系统允许在文件中“打孔”,因此,使用经过mmap处理的文件,您可以在将其用作内存中的数组时使用对其进行fallocate系统调用。

答案 4 :(得分:0)

  

您可以释放动态分配的数组的单个内存地址吗?

您似乎认识到答案是“否”,因为您跟进了

  

为什么您不能释放单个地址,是因为空间需要连续?

每个单独的分配都是连续的,但是所有动态分配的空间的并集决不能确定是连续的。稍后会对此进行更多介绍。

在最实际的水平上,您不能释放较大分配的块,因为C没有提供这样做的机制。特别是,the specifications for the free() function中包括:

  

如果参数与先前由内存管理函数返回的指针不匹配,或者如果通过调用free或realloc释放了空间,则该行为是不确定的。

因此,free()如果其参数是指向已分配块内部的指针,则显示UB。

请注意,free()仅接受一个参数。它不提供给调用方指定要释放的内存量的条件,因此内存管理子系统必须从提供的参数实参中找出这一点。对于只释放整个先前分配的块的操作模型来说,这是很好的选择,但它并不容易支持多块分配。

此外,请考虑,尽管您不能释放较大分配的特定块,但您可以 使用realloc()来减小分配的大小(这也可能涉及移动分配)。

除此以外的任何事情都是特定于实现的行为,但请记住这一点

  • 以多字节块(例如16字节的倍数)进行执行和分配很常见,而与请求的特定大小无关。以这种方式工作的实现在任何情况下都不能释放部分块,尽管可以想象能够从更大的分配中释放单个块。

  • 某些实现在与呈现给程序的动态分配空间相邻的位置存储内存管理元数据。在这种实现中,释放较大分配的块没有用,因为通常在释放整个分配之前,它们无法重用,因为所需元数据没有可用的位置。

  

如果这是答案,那么为什么在硬盘上发生碎片

您不需要分批释放内存分配。它可以执行多个分配,然后只释放其中的一些分配就足够了。这是一个实际问题,可能会降低性能,甚至导致程序失败。

但是,与C内存管理实现相比,文件系统通常使用不同的方法和数据结构来跟踪其元数据,并且底层硬件具有不同的特性和行为,因此对于形成关于一种存储的行为和功能基于另一种存储的行为和功能。