C语言中使用malloc进行内存分配

4

这是我的程序:

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

main(){
   char *p1, *p2, *p3, *p4;

   p1 = (char*)malloc(10);
   p2 = (char*)malloc(10);
   p3 = (char*)malloc(16);
   p4 = (char*)malloc(32);

   printf("p1 points at: %d\n", p1);
   printf("p2 points at: %d\n", p2);
   printf("p3 points at: %d\n", p3);
   printf("p4 points at: %d\n\n", p4);

   system("PAUSE");
}

在我的电脑上,以下是输出结果:

p1 指向:6492080

p2 指向:6492104

p3 指向:6492128

p4 指向:6492152

所以,无论分配多少字节,每个由malloc分配的内存空间都会往后移动24个字节。为什么会这样呢?感谢您的帮助!

1
编译器应该警告您有关%d格式字符串的问题。指针使用%p进行打印。您启用了警告吗?此外,不要将malloc的返回强制转换。 - William Morris
3个回答

5
malloc的确切行为由您特定的实现(编译器/ libc /操作系统)确定。通过打印地址,您的程序会产生未定义的行为。
如果您告诉我们您使用的编译器、操作系统、架构和libc版本,那么我们可能能够更具体地回答关于该实现的问题以及为什么数字是24的问题。
我猜测在您的实现中,每个malloc的内存区域都需要从8的倍数地址开始,并且还有8字节的开销。
编辑:如果在p4之后再次调用malloc创建p5,则该模式绝不能继续,因此您关于“malloc分配的每个内存空间始终比前一个多24个字节”这一说法是错误的。

好的,我正在使用Dev-C++编译器v.4.9.9.2在Windows 7 64位操作系统上。我在哪里可以找到libc版本?最后,我明白了我的问题,但你懂我的意思! - mgus

3

无法保证一个int和一些void*char*指针具有相同的大小(在我的Debian/Linux/AMD64系统上,int是32位,但指针是64位)。您可能需要包括<stdint.h>并使用intptr_t

malloc的实现有时可能会在分配的区域之前保留几个字节以进行管理。并且malloc始终应返回足够对齐的指针(对齐约束是编译器、运行时和处理器特定的)。无法保证malloc在时间上返回递增的结果序列(特别是在实际程序中,其中数百万次对malloc的调用与数百万次对free的调用混合在一起;在这样的长时间运行的进程中,您甚至可能会遇到一些内存碎片化)。

我非常确定,如果在p4之后添加一个p5 = malloc(10120);,那么你就不会看到p5p4之间有24字节的距离,因为当它成功时,malloc保证其结果不是任何先前结果的alias,所以p5应该至少与p4(包含32字节块)相隔32字节。

通常情况下,标准C库在一些更低级的原语之上实现malloc,通常是某些系统调用来获取连续的虚拟内存页面。在Linux上,这些系统调用通常是mmap(2)(可能还包括sbrk(2)),由于Linux系统大多是自由软件,所以您实际上可以研究和改进malloc的实现,例如 Musl Libc implementation of malloc(更常见的GNU libc malloc实现可能更难理解)。因此,通过切换到Linux,您可以学习更多相关知识。

< p >实现< code >malloc 可能在理论上总是失败。在实践中,< code >malloc 可能会成功,但您应始终测试失败情况。

当然,大多数实现关心< code >free 并重新使用最近的< code >free 内存区域(如果可能的话,不需要任何系统调用)在其< code >malloc 实现中。如何组织堆以使< code >malloc 和< code >free 高效是困难的(如果您希望它非常好,可能仍然是一个研究课题)。

您可能想阅读维基百科页面上的 malloc


1

malloc函数将为大小为size的对象分配空间。例如,为了对齐目的,您的实现可以添加填充字节。另一个例子是,一些内存管理实现在分配的空间之前保留块的大小。

如果您需要更多详细信息,请明确您的实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接