如何释放C#中分配特定大小的内存

yqyhoc1h  于 2022-12-26  发布在  C#
关注(0)|答案(4)|浏览(299)

我用malloc分配了一个100字节的内存,结果只使用了100字节中的40字节。
1.使用的40字节基本上是从前面开始的,40+60,其中使用40,不使用60。
1.使用的40个字节来自后面,60+40,其中使用40,不使用60。
我总是有一个指针指向这个未使用的内存和未使用内存的大小。我认为free不能用,因为它认为它应该释放100字节。问题是,在这两种情况下,是否有可能从已分配的内存中释放60字节的内存?

yzckvree

yzckvree1#

函数realloc允许您缩小分配内存的大小。
但是,在您问题中的示例中,如果您使用realloc将数组从100字节收缩到40字节,则将保留前40字节的数据,并丢失最后60字节的数据。因此,这仅适用于您问题中的场景#1。
如果您还希望它在场景#2中工作,那么您必须首先将内存缓冲区后面的40个字节复制到内存缓冲区的前面,例如使用memcpy
但是,有些操作系统确实提供了一种方法,可以释放连续内存区域的后部,而不释放前部。例如Linux上的mmap/mremap和Microsoft Windows上的VirtualFree。但是,此类函数通常适用于单个memory pages,通常至少为4096字节大。所以这些特性只有在处理大量内存时才有用,在你问题中的例子中就没用了,因为它只处理100字节。
ISO C标准库本身不提供上一段提到的功能,因此,如果您希望代码保持portable,则只能使用realloc

ybzsozfc

ybzsozfc2#

realloc可用于减小(或增大)先前由malloccallocrealloc返回的分配的大小。
但是,在这样做时,指向此内存的先前指针值将无效。
realloc相对于分配的开始调整分配的大小,因此如果数据位于分配的末尾,则必须向前移动该数据。

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

#define TOTAL 100
#define USED 40
#define UNUSED 60

int main(void)
{
    int *front_used = calloc(TOTAL, sizeof *front_used);
    memset(front_used, 0, USED * sizeof *front_used);

    int *ftemp = realloc(front_used, USED * sizeof *front_used);
    /* ftemp should be checked for NULL */
    front_used = ftemp;

    int *back_used = calloc(TOTAL, sizeof *back_used);
    memset(back_used + UNUSED, 0, USED * sizeof *back_used);
    /* must move data to start of buffer */
    memmove(back_used, back_used + UNUSED, USED * sizeof *back_used);

    int *btemp = realloc(back_used, USED * sizeof *back_used);
    /* btemp should be checked for NULL */
    back_used = btemp;
}
8i9zcol2

8i9zcol23#

**TLDR:**你不应该释放部分内存块。你不应该为这样小的优化而烦恼,因为它们可能会对你的程序产生负面影响。

虽然这种想法在那些试图尽可能精确地计算内存使用情况的初学者中很常见,但这样做确实不是一个好主意,这是因为memory manager的内部工作方式。
为了给予你一些概念,让我试着在一个相当小的上下文中解释它。那么,你认为内存管理器是如何知道从给定指针开始它需要释放多少内存块的呢?
最常见的实现和我所知道的实现是内存管理器在指针所指向的内存之前的字节中存储一块元数据。元数据包括帮助内存管理器正确完成工作的信息-存储与指针相关联的下一个内存量,存储下一个可用空闲内存块的位置等。
假设您按以下方式分配了100字节的内存:

char* characterPointer = malloc(sizeof(char)*100);

正如您在问题中提到的,您使用了这些分配的100插槽中的一些内存(比如40)。
现在,如果您尝试释放从41st索引开始的内存,则如下所示:

free(characterPointer+40);

内存管理器将向左移动一个字节,并尝试解析任何位模式,作为给定指针的 meta数据。现在你认为会发生什么?答案是,甚至我也不知道,这可能取决于。但有一件事可以肯定的是,这将导致一些不必要的行为。
它释放的内存可能比你想要的要多,也可能比你想要的要少,尽管如此,你还是会破坏内存。通常,最好不要为这么小的内存块而烦恼。
内存管理器是为了做类似的事情而构建的。有时候,当你请求100字节的内存时,内存管理器可能会返回一个大于100字节的内存块,这是完全可以的,因为它满足了你的内存需求。这样的决定是在幕后做出的,目的是提高管理器的速度,它们随内存管理器的每个实现而变化。

b09cbbtk

b09cbbtk4#

不能部分释放先前由malloc分配的块,最接近的选择是使用realloc来调整先前由malloc分配的内存块的大小。
另外,请注意,被释放的内存块不会立即被操作系统使用,它们首先会被列为空闲块,并且可以被malloc访问以供将来分配。
最后但并非最不重要的一点是,分配和释放小块内存可能会导致内存碎片,这可能是比您试图解决的问题更严重的问题。

相关问题