我使用malloc分配了100字节的内存。然而最终只用了其中的40字节。有两种情况:
- 使用的40字节在前面,剩下的60字节没有使用。
- 使用的40字节在后面,剩下的60字节没有使用。
函数realloc
允许您缩小已分配内存的大小。
然而,在您的问题示例中,如果您使用realloc
将数组从100
字节缩小到40
字节,则会保留前40
字节的数据并丢失后60
字节的数据。因此,这只适用于您问题的情况#1。
如果您还希望它在情况#2中起作用,则必须首先将内存缓冲区后面的40个字节复制到内存缓冲区的前面,例如使用memcpy
。
然而,一些操作系统确实提供了一种释放连续内存区域后面部分的方法,而不是前面部分。例如,在Linux上是mmap
/mremap
,在Microsoft Windows上是VirtualFree
。但这样的函数通常只能处理单个内存页面,它们通常至少有4096字节大小,因此这些功能只在处理更大量的内存时才有用。它们在你问题的示例中并没有用处,因为该示例仅涉及100字节。
ISO C标准库本身不提供上述段落中提到的功能。因此,如果您希望代码保持可移植性,则只能使用realloc
。
realloc
并不保证能够重用块中多余的内存。许多实现在将 100 字节的块重新分配为 40 字节时可能什么也不做(尽管如果您将 100 兆字节的块重新分配为 40 兆字节,则可能会执行某些操作)。 - riciptrdiff_t
与先前的分配情况,似乎gcc的最小分配为32
字节,并且以16
字节增量递增,可能在1K左右的mmap块内。您可以进一步调查stracing或转储到汇编。 - David C. Rankinrealloc
可以用来减少(或增加)之前由 malloc
、calloc
或 realloc
返回的内存分配的大小。
但是,在这样做时,该内存的先前指针值将无效。
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;
}
char* characterPointer = malloc(sizeof(char)*100);
free(characterPointer+40);
你不能部分释放之前由malloc分配的内存块。最接近的选项是使用realloc来调整之前由malloc分配的内存块的大小。
此外,请注意,释放的内存块不会立即变为操作系统可用。它们被列为空闲块,并且首先可以通过malloc访问以供将来分配。
最后,分配和释放小块内存可能会导致内存碎片化,这可能比您试图解决的问题更糟糕。
realloc
函数来处理场景1。 - Christopher Mooremalloc()
分配一个新块,将40个字节复制过去,然后释放原始的100个字节块... “幕后”(正如内存管理器所说),这甚至可能是realloc()
在情况#1中选择执行的操作。 - Fe2O3malloc()
返回的原始地址上调用free()
。你不能调用free()
传递原始块中第一个之后的某个地址。 - David C. Rankin