【发布时间】:2014-10-16 17:47:14
【问题描述】:
根据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 应该是例外而不是规则,因为它很容易导致未定义的行为。
两个问题:
- C 程序是否经常因
malloc而处理意外功能?这是一个相当频繁的问题吗? - 如果我每次都使用
calloc而不是malloc,我真的会受到多少性能损失?
【问题讨论】:
-
为什么需要一些内存来存储数据是一种特殊情况?例如,您是否曾经打开并阅读过文件?或者从网络套接字读取?还是转换了字符串编码?还是加密了一些数据?
-
为了继续长篇大论,我们可以扭转这个局面:你什么时候需要最初为零的东西? 那应该是例外。零只是众多合理数字中的一个,它可能是算法中某些状态的初始值。
-
@PascalCuoq:我不认为 heartbleed 是
malloc暴露旧数据的一个例子。 Heartbleed 是读取缓冲区末尾并跨入堆上其他(可能已释放,可能仍分配)内存的问题。 -
在许多情况下(对于大分配),无论如何你都会得到匿名
mmap的结果,而这在某些系统(例如 Linux)上往往是零初始化的。对于您的问题 1:如果您使用未初始化的值,任何好的静态分析器、带有警告的编译器或类似 valgrind 的东西都会对您大喊大叫。因此,如果您使用此类工具并修复警告,这不是什么大问题。 -
一个相反的观点是
calloc会让静态分析器和 Valgrind 看起来像你打算分配块的初始值为零,如果该值没有意义并且您忘记了用合理的值真正初始化它,他们将无法警告您您在程序中引入的功能错误。使用malloc,静态分析器和 Valgrind 会知道你的意图并警告你忘记初始化(部分)块。
标签: c performance security memory-management