函数原型:
void *realloc(void *mem_address, unsigned int newsize);
1,realloc怎么知道原来内存大小的?
realloc
函数在执行时可能会重新分配一块新的内存,并且在需要时将旧内存中的数据复制到新的内存区域。然而,realloc
并不会直接接收到原始内存块的大小,因为它只接受两个参数:一个是原来的内存地址,另一个是新的内存大小。那么,它是如何知道原内存块的大小以便进行复制的呢?
这依赖于系统的内存管理。
其实,在内存管理的实现中,分配的内存块大小通常是记录在内存分配器的内部数据结构中。通常的做法是,在分配给用户的内存块之前或之后,内存分配器会额外分配一小块空间,用来存储该块内存的元数据,其中包括了内存块的大小。
例如,当你使用 malloc
分配了一块内存时,内存分配器会在返回给你的内存地址之前预留一小部分空间(通常是几个字节),用来存储这块内存的大小和其他元数据。因此,尽管用户代码无法直接访问这些元数据,内存管理器可以通过这些元数据知道每个分配的内存块的大小。
当 realloc
被调用时,内存分配器可以通过内部管理的数据结构(可能就在给定的 mem_address
前面的一段区域)查找出原来分配的内存块的大小,然后根据情况决定是否需要分配新的内存块并复制数据。
内存分配器的典型工作流程:
malloc
分配内存:内存分配器会在返回给用户的内存地址之前,预留一些字节用于存储该块内存的大小和其他信息。realloc
查找内存块大小:当调用realloc
时,分配器通过查找该内存块前面的元数据,得知该内存块的大小。- 重新分配和复制数据:如果新大小比旧大小大且当前块无法扩展,
realloc
会分配一个新的足够大的内存块,并将旧块中的数据复制到新的内存块中。
-------------------------------------------------------------------------------------------------------------
2,realloc的内部工作步骤:
- 1),检查输入指针:
- 如果传递的指针
mem_address
为NULL
,realloc
的行为和malloc
类似,它会分配一块新的内存。 - 如果
newsize
为 0,realloc
通常相当于free
,即释放传入的内存块,并返回NULL
。
- 如果传递的指针
- 2),查找当前内存块大小:
- 如果
mem_address
是有效的指针,realloc
会通过内存分配器的元数据找到当前分配的内存块的大小。通常,这些元数据会存储在内存块的前面,或者通过某种全局或局部的表来记录所有分配的内存块。
- 如果
- 3),判断是否需要重新分配:
- 如果
newsize
小于或等于当前内存块的大小,通常不需要分配新的内存,直接返回原来的指针即可(可能需要调整内存分配器的元数据,更新分配的大小)。 - 如果
newsize
大于当前内存块的大小,内存分配器会尝试在原来的位置扩展内存块。如果原来的内存块后有足够的空闲空间,那么可以在原地扩展并返回相同的指针。
- 如果
- 4),分配新内存块:
- 如果无法在原地扩展内存块(例如,后面的内存被其他数据占用),
realloc
会调用malloc
分配一块新的、大小为newsize
的内存块。
- 如果无法在原地扩展内存块(例如,后面的内存被其他数据占用),
- 5),复制旧数据到新内存块:
- 如果
realloc
分配了新的内存块,接下来会将旧内存块中的数据复制到新内存块中。复制的大小是min(原内存块大小, newsize)
,即只复制需要的部分,以免读写越界。
- 如果
- 6),释放旧内存块:
- 在数据复制完成后,
realloc
会调用free
释放旧的内存块(如果新的内存块位于不同的位置)。
- 在数据复制完成后,
- 7)返回新内存块的地址:
realloc
最后会返回新分配的内存块的地址。如果分配失败,则返回NULL
,并且原内存块不变。