根据Linux手册页,calloc
和malloc
之间的区别在于malloc
没有初始化内存,而calloc
>初始化内存。
在实践中,这意味着如果我创建这样的结构:
struct Danger {
char a;
char b;
char c;
char d;
}
如果我使用malloc
:
struct Danger *dang = malloc(sizeof(struct Danger));
此时dang->a
似乎真的可以是任何值,因为内存未初始化。如果我使用calloc
:
struct Danger *dang = calloc(1, sizeof(struct Danger));
我现在知道dang->a
必须等于\0
。
可能存在malloc
的原因是你要写入你立即分配的整个存储空间,你最初并不关心那里的内容。这样可以省去额外的步骤,将数据归零,无论如何都会被覆盖
从程序安全性和稳定性的角度来看,使用malloc
应该是例外而不是规则,因为它很容易导致未定义的行为。
两个问题:
malloc
的意外功能吗?这是一个相当复杂的问题吗?calloc
代替malloc
,我真正得到多少性能损失?答案 0 :(得分:2)
野外的C程序经常会遇到意外的功能吗?这是一个相当复杂的问题吗?
他们经常处理“问题”,但通常是他们试图不读取垃圾数据的方式。这通常没有问题,因为无论如何都需要初始化数据。真正的危险在于无意中读取垃圾/零数据,使用calloc()
无法排除这些数据。
有一些方法可以确保程序不会读取垃圾数据。最简单的方法是使用valgrind
执行测试套件。它报告任何垃圾数据的读取。它还将捕获任何使用后释放错误,未分配内存的访问,丢失的内存块等。
如果我每次只使用
calloc
代替malloc
,我真正得到多少性能损失?
准确地写两次写入数据的开销。它可能会从缓存中删除一些有价值的数据,因此它实际上取决于内存块的大小,以及之后用来填充合理数据的操作顺序。
最坏情况:归零会从缓存中驱逐需要填充内存块的数据。这些数据需要从内存中重新加载,这是性能影响的主要部分。对于大约几兆字节的存储器块,这可能相当于大约100微秒的影响。细节取决于您的机器。
最佳情况:在分配后立即填充一个小内存块而不读取任何数据。在这种情况下,开销就是将数据写入第一级缓存的开销。即使这是一个快速操作,您仍然可以期望归零与您自己的初始化时间相同 - 缓存不是无限快。
当我需要零初始化块时,我只使用calloc()
作为获取零初始化块的便捷方式。通常情况并非如此。但它经常发生。